diff --git a/.github/workflows/test_galaxy_packages_for_pulsar.yaml b/.github/workflows/test_galaxy_packages_for_pulsar.yaml
index 93ad8db7901..2dc6c0bf4bf 100644
--- a/.github/workflows/test_galaxy_packages_for_pulsar.yaml
+++ b/.github/workflows/test_galaxy_packages_for_pulsar.yaml
@@ -17,11 +17,13 @@ permissions: {}
jobs:
test:
name: Test
+ # This job is disabled because it is currently redundant with `test_galaxy_packages.yaml`
+ if: false
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
- python-version: ['3.8'] # don't upgrade, see https://github.com/galaxyproject/galaxy/pull/16649
+ python-version: ['3.10']
steps:
- uses: actions/checkout@v6.0.3
with:
diff --git a/Makefile b/Makefile
index b22f77cb3a7..218fd972a51 100644
--- a/Makefile
+++ b/Makefile
@@ -30,10 +30,6 @@ SPACE := $() $()
NEVER_PYUPGRADE_PATHS := .venv/ .tox/ lib/galaxy/schema/bco/ \
lib/galaxy/schema/drs/ lib/tool_shed_client/schema/trs \
scripts/check_python.py tools/ test/functional/tools/cwl_tools/
-PY38_PYUPGRADE_PATHS := lib/galaxy/exceptions/ lib/galaxy/job_metrics/ \
- lib/galaxy/objectstore/ lib/galaxy/tool_util/ lib/galaxy/tool_util_models/ \
- lib/galaxy/util/ test/unit/job_metrics/ test/unit/objectstore/ \
- test/unit/tool_util/ test/unit/tool_util_models/ test/unit/util/
all: help
@echo "This makefile is used for building Galaxy's JS client, documentation, and drive the release process. A sensible all target is not implemented."
@@ -62,10 +58,9 @@ format: ## Format Python code base
remove-unused-imports: ## Remove unused imports in Python code base
$(IN_VENV) autoflake --in-place --remove-all-unused-imports --recursive --verbose lib/ test/
-pyupgrade: ## Convert older code patterns to Python 3.8/3.10 idiomatic ones
- ack --type=python -f | grep -v '^$(subst $(SPACE),\|^,$(NEVER_PYUPGRADE_PATHS) $(PY38_PYUPGRADE_PATHS))' | xargs pyupgrade --py310-plus
- ack --type=python -f | grep -v '^$(subst $(SPACE),\|^,$(NEVER_PYUPGRADE_PATHS) $(PY38_PYUPGRADE_PATHS))' | xargs auto-walrus
- ack --type=python -f $(PY38_PYUPGRADE_PATHS) | xargs pyupgrade --py38-plus
+pyupgrade: ## Convert older code patterns to Python 3.10+ idiomatic ones
+ ack --type=python -f | grep -v '^$(subst $(SPACE),\|^,$(NEVER_PYUPGRADE_PATHS))' | xargs pyupgrade --py310-plus
+ ack --type=python -f | grep -v '^$(subst $(SPACE),\|^,$(NEVER_PYUPGRADE_PATHS))' | xargs auto-walrus
docs-slides-ready:
test -f plantuml.jar || wget http://jaist.dl.sourceforge.net/project/plantuml/plantuml.jar
diff --git a/lib/galaxy/agents/base.py b/lib/galaxy/agents/base.py
index b6e31587413..ed32b599e7d 100644
--- a/lib/galaxy/agents/base.py
+++ b/lib/galaxy/agents/base.py
@@ -24,7 +24,6 @@ from typing import (
Literal,
Optional,
TYPE_CHECKING,
- Union,
)
import yaml
@@ -103,7 +102,7 @@ _DEFAULT_MODEL_CAPABILITIES: dict[str, Any] = {
_model_capabilities_cache: dict[str, dict[str, Any]] = {}
-def _load_model_capabilities(path: Optional[str], force_reload: bool = False) -> dict[str, Any]:
+def _load_model_capabilities(path: str | None, force_reload: bool = False) -> dict[str, Any]:
"""Return the parsed model-capabilities table for ``path``, falling back to defaults on any failure."""
if not isinstance(path, str) or not path:
return _DEFAULT_MODEL_CAPABILITIES
@@ -133,7 +132,7 @@ def _load_model_capabilities(path: Optional[str], force_reload: bool = False) ->
return parsed
-def _capability_for_model(model_name: str, capability: str, table: dict[str, Any]) -> Optional[bool]:
+def _capability_for_model(model_name: str, capability: str, table: dict[str, Any]) -> bool | None:
"""Look up `capability` for `model_name` against the parsed table.
Strips any `provider:` prefix before matching. Returns None when neither
@@ -259,7 +258,7 @@ def extract_usage_info(result: Any) -> dict[str, int]:
return {}
-def extract_structured_output(result: Any, expected_type: type, logger: Optional[logging.Logger] = None) -> Any:
+def extract_structured_output(result: Any, expected_type: type, logger: logging.Logger | None = None) -> Any:
"""Extract structured output from a pydantic-ai result, or None if extraction fails."""
_log = logger or log
@@ -315,11 +314,11 @@ class AgentResponse:
def __init__(
self,
content: str,
- confidence: Union[str, ConfidenceLevel],
+ confidence: str | ConfidenceLevel,
agent_type: str,
- suggestions: Optional[list[ActionSuggestion]] = None,
- metadata: Optional[dict[str, Any]] = None,
- reasoning: Optional[str] = None,
+ suggestions: list[ActionSuggestion] | None = None,
+ metadata: dict[str, Any] | None = None,
+ reasoning: str | None = None,
):
self.content = content
if isinstance(confidence, ConfidenceLevel):
@@ -361,13 +360,13 @@ class GalaxyAgentDependencies:
get_agent: Callable[[str, "GalaxyAgentDependencies"], "BaseGalaxyAgent"]
# Callable returning an agent's user-facing capability blurb, or None when that agent
# is not enabled in this deployment. Lets the router advertise only real capabilities.
- get_capability_blurb: Optional[Callable[[str], Optional[str]]] = None
+ get_capability_blurb: Callable[[str], str | None] | None = None
job_manager: Optional["JobManager"] = None
dataset_manager: Optional["DatasetManager"] = None
workflow_manager: Optional["WorkflowsManager"] = None
tool_cache: Optional["ToolCache"] = None
toolbox: Optional["ToolBox"] = None
- model_factory: Optional[Callable[[], Any]] = None
+ model_factory: Callable[[], Any] | None = None
class BaseGalaxyAgent(ABC):
@@ -378,7 +377,7 @@ class BaseGalaxyAgent(ABC):
# composes its "what can you do" answer from the blurbs of the agents enabled in this
# deployment. None means the agent is not advertised there (e.g. the router itself, or
# surfaces like the notebook page assistant that users reach a different way).
- capability_blurb: Optional[str] = None
+ capability_blurb: str | None = None
agent: Agent[GalaxyAgentDependencies, Any]
_INTERNAL_CONTEXT_KEYS = frozenset({"run_state", "responding_to_clarification"})
@@ -407,7 +406,7 @@ class BaseGalaxyAgent(ABC):
def get_system_prompt(self) -> str:
pass
- def _validate_query(self, query: str) -> Optional[str]:
+ def _validate_query(self, query: str) -> str | None:
"""Validate query input. Returns None if valid, error message if not."""
if not query or not isinstance(query, str):
return "Query must be a non-empty string"
@@ -444,7 +443,7 @@ class BaseGalaxyAgent(ABC):
metadata={"validation_error": True},
)
- async def process(self, query: str, context: Optional[dict[str, Any]] = None) -> AgentResponse:
+ async def process(self, query: str, context: dict[str, Any] | None = None) -> AgentResponse:
validation_error = self._validate_query(query)
if validation_error:
return self._validation_error_response(validation_error)
@@ -462,9 +461,9 @@ class BaseGalaxyAgent(ABC):
@staticmethod
def _extract_message_history(
- context: Optional[dict[str, Any]],
+ context: dict[str, Any] | None,
limit: int = MAX_HISTORY_MESSAGES,
- ) -> Optional[list[ModelMessage]]:
+ ) -> list[ModelMessage] | None:
"""Pull ``conversation_history`` out of context, normalize it, and truncate it.
Returns None when history is missing/empty so callers can pass it
@@ -498,7 +497,7 @@ class BaseGalaxyAgent(ABC):
prompt: str,
max_retries: int = 3,
base_delay: float = 1.0,
- message_history: Optional[list[ModelMessage]] = None,
+ message_history: list[ModelMessage] | None = None,
):
"""Run the agent with exponential backoff for retryable errors."""
last_exception = None
@@ -708,10 +707,10 @@ class BaseGalaxyAgent(ABC):
self,
method: str,
result: Any = None,
- query: Optional[str] = None,
- agent_data: Optional[dict[str, Any]] = None,
+ query: str | None = None,
+ agent_data: dict[str, Any] | None = None,
fallback: bool = False,
- error: Optional[str] = None,
+ error: str | None = None,
) -> dict[str, Any]:
"""Build consistent metadata for agent responses.
@@ -747,12 +746,12 @@ class BaseGalaxyAgent(ABC):
confidence: ConfidenceLevel,
method: str,
result: Any = None,
- query: Optional[str] = None,
- suggestions: Optional[list[ActionSuggestion]] = None,
- agent_data: Optional[dict[str, Any]] = None,
+ query: str | None = None,
+ suggestions: list[ActionSuggestion] | None = None,
+ agent_data: dict[str, Any] | None = None,
fallback: bool = False,
- error: Optional[str] = None,
- reasoning: Optional[str] = None,
+ error: str | None = None,
+ reasoning: str | None = None,
) -> AgentResponse:
return AgentResponse(
content=content,
@@ -789,7 +788,7 @@ class BaseGalaxyAgent(ABC):
"""Override in agents that require structured output to function."""
return False
- def _validate_model_capabilities(self) -> Optional[str]:
+ def _validate_model_capabilities(self) -> str | None:
"""Check that the model meets this agent's requirements. Returns error message or None."""
if self._requires_structured_output() and not self._supports_structured_output():
model = self._get_agent_config("model", "unknown")
@@ -883,7 +882,7 @@ class BaseGalaxyAgent(ABC):
def _get_max_tokens(self) -> int:
return self._get_agent_config("max_tokens", self.DEFAULT_MAX_TOKENS)
- def _get_retries(self, default: Optional[int] = None) -> int:
+ def _get_retries(self, default: int | None = None) -> int:
"""Retry budget for the agent's pydantic-ai ``Agent(retries=...)``.
With no ``default``, the budget resolves per-agent > ``default`` block >
@@ -913,7 +912,7 @@ class BaseGalaxyAgent(ABC):
query: str,
ctx,
usage=None,
- context: Optional[dict[str, Any]] = None,
+ context: dict[str, Any] | None = None,
) -> str:
"""Call another agent from within a @agent.tool function."""
try:
diff --git a/lib/galaxy/agents/custom_tool.py b/lib/galaxy/agents/custom_tool.py
index ec5b2295cfc..13f635aeb07 100644
--- a/lib/galaxy/agents/custom_tool.py
+++ b/lib/galaxy/agents/custom_tool.py
@@ -7,7 +7,6 @@ from dataclasses import dataclass
from pathlib import Path
from typing import (
Any,
- Optional,
)
import yaml
@@ -45,14 +44,14 @@ from .base import (
log = logging.getLogger(__name__)
-def _find_validation_error(exc: BaseException) -> Optional[ValidationError]:
+def _find_validation_error(exc: BaseException) -> ValidationError | None:
"""Walk the exception cause chain looking for a pydantic ValidationError.
pydantic-ai wraps validation failures inside UnexpectedModelBehavior after
exhausting retries; the original ValidationError surfaces via __cause__.
"""
seen: set[int] = set()
- current: Optional[BaseException] = exc
+ current: BaseException | None = exc
while current is not None and id(current) not in seen:
seen.add(id(current))
if isinstance(current, ValidationError):
@@ -61,7 +60,7 @@ def _find_validation_error(exc: BaseException) -> Optional[ValidationError]:
return None
-def _invalid_attempt_yaml(messages: list[Any]) -> Optional[str]:
+def _invalid_attempt_yaml(messages: list[Any]) -> str | None:
"""Best-effort render of the model's last ``final_result`` tool-call arguments
(the attempt that just failed schema validation) as YAML.
@@ -120,7 +119,7 @@ class _ProducerFailure:
"""
errors: list[str]
- prior_yaml: Optional[str] = None
+ prior_yaml: str | None = None
class CustomToolAgent(BaseGalaxyAgent):
@@ -157,7 +156,7 @@ class CustomToolAgent(BaseGalaxyAgent):
def __init__(self, deps: GalaxyAgentDependencies):
super().__init__(deps)
- self._critic_agent: Optional[Agent[GalaxyAgentDependencies, CritiqueReport]] = None
+ self._critic_agent: Agent[GalaxyAgentDependencies, CritiqueReport] | None = None
def _requires_structured_output(self) -> bool:
return True
@@ -218,7 +217,7 @@ class CustomToolAgent(BaseGalaxyAgent):
def _quality_critic_enabled(self) -> bool:
return bool(self._get_agent_config("quality_critic_enabled", False))
- async def process(self, query: str, context: Optional[dict[str, Any]] = None) -> AgentResponse:
+ async def process(self, query: str, context: dict[str, Any] | None = None) -> AgentResponse:
validation_error = self._validate_query(query)
if validation_error:
return self._validation_error_response(validation_error)
@@ -311,10 +310,10 @@ class CustomToolAgent(BaseGalaxyAgent):
async def _produce_tool(
self,
query: str,
- retry_errors: Optional[list[str]] = None,
- critique: Optional[CritiqueReport] = None,
- prior_yaml: Optional[str] = None,
- ) -> Optional[tuple[UserToolSource, str, Any] | _ProducerFailure]:
+ retry_errors: list[str] | None = None,
+ critique: CritiqueReport | None = None,
+ prior_yaml: str | None = None,
+ ) -> tuple[UserToolSource, str, Any] | _ProducerFailure | None:
"""Run the producer agent. Returns (tool, yaml, raw_result), a
``_ProducerFailure``, or None.
@@ -358,9 +357,9 @@ class CustomToolAgent(BaseGalaxyAgent):
@staticmethod
def _build_producer_prompt(
query: str,
- retry_errors: Optional[list[str]] = None,
- critique: Optional[CritiqueReport] = None,
- prior_yaml: Optional[str] = None,
+ retry_errors: list[str] | None = None,
+ critique: CritiqueReport | None = None,
+ prior_yaml: str | None = None,
) -> str:
if not retry_errors and not critique:
return query
@@ -405,7 +404,7 @@ class CustomToolAgent(BaseGalaxyAgent):
sections.append("Original request (for reference):\n\n" + query)
return "\n\n".join(sections)
- async def _run_critic(self, tool_yaml: str, query: str) -> Optional[CritiqueReport]:
+ async def _run_critic(self, tool_yaml: str, query: str) -> CritiqueReport | None:
"""Run the quality critic. Returns None if the critic call fails."""
critic = self._get_critic_agent()
critic_prompt = (
diff --git a/lib/galaxy/agents/error_analysis.py b/lib/galaxy/agents/error_analysis.py
index 8b0a1f3aa2f..cbcc686aba7 100644
--- a/lib/galaxy/agents/error_analysis.py
+++ b/lib/galaxy/agents/error_analysis.py
@@ -8,7 +8,6 @@ from functools import partial
from pathlib import Path
from typing import (
Any,
- Optional,
)
import anyio
@@ -104,7 +103,7 @@ class ErrorAnalysisAgent(BaseGalaxyAgent):
log.warning(f"Error getting job details for {job_id}: {e}")
return {"error": f"Failed to retrieve job details: {str(e)}"}
- async def process(self, query: str, context: Optional[dict[str, Any]] = None) -> AgentResponse:
+ async def process(self, query: str, context: dict[str, Any] | None = None) -> AgentResponse:
validation_error = self._validate_query(query)
if validation_error:
return self._validation_error_response(validation_error)
diff --git a/lib/galaxy/agents/gtn/__main__.py b/lib/galaxy/agents/gtn/__main__.py
index 6f2e9e2cdbc..4d400c8e6c3 100644
--- a/lib/galaxy/agents/gtn/__main__.py
+++ b/lib/galaxy/agents/gtn/__main__.py
@@ -29,8 +29,7 @@ def _resolve_config_file(explicit_config_file: str | None) -> str:
raise RuntimeError(f"Config file does not exist: {config_file}")
return str(config_file)
- env_config_file = os.environ.get("GALAXY_CONFIG_FILE")
- if env_config_file:
+ if env_config_file := os.environ.get("GALAXY_CONFIG_FILE"):
config_file = Path(env_config_file)
if not config_file.exists():
raise RuntimeError(f"GALAXY_CONFIG_FILE does not exist: {config_file}")
diff --git a/lib/galaxy/agents/gtn/build_database.py b/lib/galaxy/agents/gtn/build_database.py
index 8c87acc043e..fc54dfdc411 100644
--- a/lib/galaxy/agents/gtn/build_database.py
+++ b/lib/galaxy/agents/gtn/build_database.py
@@ -23,8 +23,6 @@ from hashlib import md5
from pathlib import Path
from typing import (
Any,
- Optional,
- Union,
)
# Configure logging
@@ -79,7 +77,7 @@ class Tutorial:
class GTNDatabaseBuilder:
"""Builds SQLite database from GTN repository."""
- def __init__(self, gtn_path: Path, output_path: Optional[Path] = None):
+ def __init__(self, gtn_path: Path, output_path: Path | None = None):
self.gtn_path = gtn_path
self.output_path = output_path or Path("gtn_search.db")
self.tutorials: list[Tutorial] = []
@@ -164,7 +162,7 @@ class GTNDatabaseBuilder:
except (OSError, ValueError, KeyError) as e:
log.warning(f"Failed to parse FAQ gtn/{faq_file.name}: {e}")
- def parse_faq(self, faq_file: Path, category: str) -> Optional[FAQ]:
+ def parse_faq(self, faq_file: Path, category: str) -> FAQ | None:
"""Parse a FAQ markdown file, returning None on failure."""
try:
with open(faq_file, encoding="utf-8") as f:
@@ -214,7 +212,7 @@ class GTNDatabaseBuilder:
log.warning(f"Error parsing FAQ {faq_file}: {e}")
return None
- def parse_tutorial(self, tutorial_file: Path, topic: str, tutorial_name: str) -> Optional[Tutorial]:
+ def parse_tutorial(self, tutorial_file: Path, topic: str, tutorial_name: str) -> Tutorial | None:
"""Parse a tutorial markdown file, returning None on failure."""
try:
with open(tutorial_file, encoding="utf-8") as f:
@@ -275,7 +273,7 @@ class GTNDatabaseBuilder:
def parse_yaml_simple(self, yaml_content: str) -> dict[str, Any]:
"""Simple YAML frontmatter parser (no external dependencies)."""
result: dict[str, Any] = {}
- current_list: Optional[list[str]] = None
+ current_list: list[str] | None = None
for line in yaml_content.split("\n"):
line = line.rstrip()
@@ -308,7 +306,7 @@ class GTNDatabaseBuilder:
was_quoted = True
# Check for boolean values
- parsed_value: Union[str, bool, list[str]]
+ parsed_value: str | bool | list[str]
if str_value.lower() == "true":
parsed_value = True
elif str_value.lower() == "false":
diff --git a/lib/galaxy/agents/gtn/search.py b/lib/galaxy/agents/gtn/search.py
index 3da6515bcdf..3b57d882e4c 100644
--- a/lib/galaxy/agents/gtn/search.py
+++ b/lib/galaxy/agents/gtn/search.py
@@ -22,7 +22,6 @@ from email.utils import parsedate_to_datetime
from pathlib import Path
from typing import (
Any,
- Optional,
)
GTN_DATABASE_URL = "https://depot.galaxyproject.org/chatgxy/gtn_search.db"
@@ -41,7 +40,7 @@ _ONE_SECOND = timedelta(seconds=1)
log = logging.getLogger(__name__)
-def _parse_last_modified(header: Optional[str]) -> Optional[datetime]:
+def _parse_last_modified(header: str | None) -> datetime | None:
"""Parse an HTTP Last-Modified header into an aware UTC datetime, or None."""
if not header:
return None
@@ -59,7 +58,7 @@ def _escape_like(value: str) -> str:
return value.replace("\\", "\\\\").replace("%", r"\%").replace("_", r"\_")
-def _or_form(fts_query: str) -> Optional[str]:
+def _or_form(fts_query: str) -> str | None:
"""OR-joined fallback for a multi-token FTS5 query, or None.
Returns None for quoted phrases (preserve as-is) and single-token
@@ -178,7 +177,7 @@ class FAQResult:
class GTNSearchDB:
"""Interface to the GTN search database."""
- def __init__(self, db_path: Optional[str] = None, download_url: Optional[str] = None):
+ def __init__(self, db_path: str | None = None, download_url: str | None = None):
if db_path is None:
current_dir = Path(__file__).parent
self.db_path = current_dir / "data" / "gtn_search.db"
@@ -201,7 +200,7 @@ class GTNSearchDB:
raise RuntimeError(f"Failed to initialize GTN database: {e}") from e
@staticmethod
- def _read_meta(cursor: sqlite3.Cursor, key: str) -> Optional[str]:
+ def _read_meta(cursor: sqlite3.Cursor, key: str) -> str | None:
try:
cursor.execute("SELECT value FROM metadata WHERE key = ?", (key,))
except sqlite3.Error:
@@ -222,14 +221,12 @@ class GTNSearchDB:
self._download_database()
@classmethod
- def refresh_database(cls, db_path: str | Path, download_url: Optional[str] = None) -> dict[str, Any]:
+ def refresh_database(cls, db_path: str | Path, download_url: str | None = None) -> dict[str, Any]:
"""Download, validate, and atomically replace a GTN database without opening the old copy."""
return cls._download_database_to_path(Path(db_path), download_url or GTN_DATABASE_URL)
@classmethod
- def refresh_database_if_stale(
- cls, db_path: str | Path, download_url: Optional[str] = None
- ) -> Optional[dict[str, Any]]:
+ def refresh_database_if_stale(cls, db_path: str | Path, download_url: str | None = None) -> dict[str, Any] | None:
"""HEAD the URL and re-download only if its Last-Modified is newer than the local file's mtime.
Returns the new metadata dict when a refresh happened, ``None`` when the
@@ -252,7 +249,7 @@ class GTNSearchDB:
return cls._download_database_to_path(target, url)
@staticmethod
- def _remote_last_modified(url: str) -> Optional[datetime]:
+ def _remote_last_modified(url: str) -> datetime | None:
"""HEAD ``url`` and return its parsed Last-Modified, or None on failure."""
try:
req = urllib.request.Request(url, method="HEAD")
@@ -325,8 +322,8 @@ class GTNSearchDB:
self,
query: str,
limit: int = 5,
- topic: Optional[str] = None,
- difficulty: Optional[str] = None,
+ topic: str | None = None,
+ difficulty: str | None = None,
hands_on_only: bool = False,
) -> list[SearchResult]:
"""Search tutorials using FTS5 full-text search with optional filters."""
@@ -414,8 +411,8 @@ class GTNSearchDB:
self,
query: str,
limit: int = 5,
- category: Optional[str] = None,
- area: Optional[str] = None,
+ category: str | None = None,
+ area: str | None = None,
) -> list[FAQResult]:
"""Search FAQs using FTS5 full-text search with optional filters."""
if not query:
@@ -486,7 +483,7 @@ class GTNSearchDB:
log.warning(f"FAQ search failed for query '{query}': {e}")
return []
- def get_tutorial_content(self, topic: str, tutorial: str, max_length: Optional[int] = None) -> Optional[str]:
+ def get_tutorial_content(self, topic: str, tutorial: str, max_length: int | None = None) -> str | None:
"""Retrieve tutorial content, optionally truncated to max_length."""
try:
with self._get_connection() as conn:
diff --git a/lib/galaxy/agents/gtn_training.py b/lib/galaxy/agents/gtn_training.py
index 60f05721f31..d9b4cf1cff2 100644
--- a/lib/galaxy/agents/gtn_training.py
+++ b/lib/galaxy/agents/gtn_training.py
@@ -6,7 +6,6 @@ import re
from pathlib import Path
from typing import (
Any,
- Optional,
)
from pydantic import (
@@ -42,9 +41,9 @@ class GTNSearchResponse(BaseModel):
tutorials: list[dict[str, Any]] = Field(default_factory=list, description="List of matching tutorials")
faqs: list[dict[str, Any]] = Field(default_factory=list, description="List of matching FAQs")
summary: str = Field(..., description="Natural language summary of findings")
- learning_path: Optional[str] = Field(None, description="Suggested learning progression")
+ learning_path: str | None = Field(None, description="Suggested learning progression")
prerequisites: list[str] = Field(default_factory=list, description="Recommended prerequisites")
- total_time: Optional[str] = Field(None, description="Estimated total time for suggested tutorials")
+ total_time: str | None = Field(None, description="Estimated total time for suggested tutorials")
class GTNTrainingAgent(BaseGalaxyAgent):
@@ -90,7 +89,7 @@ class GTNTrainingAgent(BaseGalaxyAgent):
log.warning(f"GTN database not available: {e}")
self.gtn_db = None
- def _charge_tool_budget(self) -> Optional[str]:
+ def _charge_tool_budget(self) -> str | None:
"""Count a data-gathering tool call; once over budget return a stop
message instead of more data so the model answers from what it has."""
self._tool_calls += 1
@@ -123,8 +122,8 @@ class GTNTrainingAgent(BaseGalaxyAgent):
async def search_gtn_tutorials(
ctx: RunContext[GalaxyAgentDependencies],
query: str,
- topic: Optional[str] = None,
- difficulty: Optional[str] = None,
+ topic: str | None = None,
+ difficulty: str | None = None,
hands_on_only: bool = False,
limit: int = 5,
) -> str:
@@ -188,7 +187,7 @@ class GTNTrainingAgent(BaseGalaxyAgent):
async def search_gtn_faqs(
ctx: RunContext[GalaxyAgentDependencies],
query: str,
- category: Optional[str] = None,
+ category: str | None = None,
limit: int = 5,
) -> str:
"""Search Galaxy / GTN FAQs for short, definitional or how-do-I questions.
@@ -246,7 +245,7 @@ class GTNTrainingAgent(BaseGalaxyAgent):
prompt_path = Path(__file__).parent / "prompts" / "gtn_training.md"
return prompt_path.read_text()
- async def process(self, query: str, context: Optional[dict[str, Any]] = None) -> AgentResponse:
+ async def process(self, query: str, context: dict[str, Any] | None = None) -> AgentResponse:
validation_error = self._validate_query(query)
if validation_error:
return self._validation_error_response(validation_error)
diff --git a/lib/galaxy/agents/history.py b/lib/galaxy/agents/history.py
index ae0d48b4e09..282294ba126 100644
--- a/lib/galaxy/agents/history.py
+++ b/lib/galaxy/agents/history.py
@@ -11,7 +11,6 @@ from pathlib import Path
from typing import (
Any,
Literal,
- Optional,
)
from pydantic_ai import Agent
@@ -132,8 +131,8 @@ class HistoryAgent(BaseGalaxyAgent):
async def get_history_graph(
ctx: RunContext[GalaxyAgentDependencies],
history_id: str,
- seed_src: Optional[Literal["hda", "hdca", "tool_request"]] = None,
- seed_id: Optional[str] = None,
+ seed_src: Literal["hda", "hdca", "tool_request"] | None = None,
+ seed_id: str | None = None,
direction: Literal["backward", "forward", "both"] = "both",
depth: int = 5,
limit: int = 200,
diff --git a/lib/galaxy/agents/history_tools.py b/lib/galaxy/agents/history_tools.py
index 53063fb877d..50c87ccc255 100644
--- a/lib/galaxy/agents/history_tools.py
+++ b/lib/galaxy/agents/history_tools.py
@@ -11,7 +11,6 @@ re-implement them.
import logging
import re
from functools import partial
-from typing import Union
import anyio
from sqlalchemy import (
@@ -105,8 +104,7 @@ def _get_dataset_info_impl(trans: ProvidesUserContext, history_id: int, hid: int
contents_manager = trans.app[HistoryContentsManager]
encode_id = trans.security.encode_id
- hda = contents_manager.get_hda_by_hid(history_id, hid)
- if hda:
+ if hda := contents_manager.get_hda_by_hid(history_id, hid):
lines = [
f"Dataset: {hda.name} (HID {hid}, history_dataset_id={encode_id(hda.id)})",
f"Format: {hda.extension}",
@@ -136,8 +134,7 @@ def _get_dataset_info_impl(trans: ProvidesUserContext, history_id: int, hid: int
lines.append("Status: HIDDEN")
return "\n".join(lines)
- hdca = contents_manager.get_hdca_by_hid(history_id, hid)
- if hdca:
+ if hdca := contents_manager.get_hdca_by_hid(history_id, hid):
collection_type = hdca.collection.collection_type if hdca.collection else "unknown"
lines = [
f"Collection: {hdca.name} (HID {hid}, history_dataset_collection_id={encode_id(hdca.id)})",
@@ -233,8 +230,7 @@ def _resolve_hid_impl(trans: ProvidesUserContext, history_id: int, hid: int) ->
contents_manager = trans.app[HistoryContentsManager]
encode_id = trans.security.encode_id
- hda = contents_manager.get_hda_by_hid(history_id, hid)
- if hda:
+ if hda := contents_manager.get_hda_by_hid(history_id, hid):
lines = [
f"HID {hid} is a dataset: {hda.name}",
f"Directive argument: history_dataset_id={encode_id(hda.id)}",
@@ -243,8 +239,7 @@ def _resolve_hid_impl(trans: ProvidesUserContext, history_id: int, hid: int) ->
lines.append(f"Creating job: job_id={encode_id(hda.creating_job.id)}")
return "\n".join(lines)
- hdca = contents_manager.get_hdca_by_hid(history_id, hid)
- if hdca:
+ if hdca := contents_manager.get_hdca_by_hid(history_id, hid):
return (
f"HID {hid} is a collection: {hdca.name}\n"
f"Directive argument: history_dataset_collection_id={encode_id(hdca.id)}"
@@ -258,7 +253,7 @@ async def resolve_hid(trans: ProvidesUserContext, history_id: int, hid: int) ->
return await anyio.to_thread.run_sync(partial(_resolve_hid_impl, trans, history_id, hid))
-def _format_size(size_bytes: Union[int, float, None]) -> str:
+def _format_size(size_bytes: int | float | None) -> str:
"""Human-readable byte size via galaxy.util.nice_size; "" for missing/negative."""
if size_bytes is None or size_bytes < 0:
return ""
diff --git a/lib/galaxy/agents/iwc.py b/lib/galaxy/agents/iwc.py
index cc5386aa77f..4c4eba54817 100644
--- a/lib/galaxy/agents/iwc.py
+++ b/lib/galaxy/agents/iwc.py
@@ -10,7 +10,6 @@ import re
from threading import Lock
from typing import (
Any,
- Optional,
)
from cachetools import TTLCache
@@ -160,7 +159,7 @@ def _score(query_tokens: list[str], text: str) -> int:
return sum(1 for t in query_tokens if t in text_tokens)
-def search_workflows(workflows: list[dict[str, Any]], query: str, limit: Optional[int] = None) -> list[dict[str, Any]]:
+def search_workflows(workflows: list[dict[str, Any]], query: str, limit: int | None = None) -> list[dict[str, Any]]:
"""Rank workflows by token overlap against name/description/readme/tags.
Each returned entry has ``match_score`` attached so callers can surface
diff --git a/lib/galaxy/agents/operations.py b/lib/galaxy/agents/operations.py
index c6eff8ac93e..666f4bd8861 100644
--- a/lib/galaxy/agents/operations.py
+++ b/lib/galaxy/agents/operations.py
@@ -8,7 +8,6 @@ import logging
from typing import (
Any,
Literal,
- Optional,
)
from sqlalchemy import select
@@ -65,17 +64,17 @@ class AgentOperationsManager:
def __init__(self, app: MinimalManagerApp, trans: ProvidesUserContext):
self.app = app
self.trans = trans
- self._tools_service: Optional[Any] = None
- self._histories_service: Optional[Any] = None
- self._jobs_service: Optional[Any] = None
- self._datasets_service: Optional[Any] = None
- self._workflows_service: Optional[Any] = None
- self._invocations_service: Optional[Any] = None
- self._hda_manager: Optional[HDAManager] = None
- self._dataset_collections_service: Optional[Any] = None
- self._dynamic_tools_manager: Optional[Any] = None
- self._file_source_instances_manager: Optional[Any] = None
- self._pages_service: Optional[Any] = None
+ self._tools_service: Any | None = None
+ self._histories_service: Any | None = None
+ self._jobs_service: Any | None = None
+ self._datasets_service: Any | None = None
+ self._workflows_service: Any | None = None
+ self._invocations_service: Any | None = None
+ self._hda_manager: HDAManager | None = None
+ self._dataset_collections_service: Any | None = None
+ self._dynamic_tools_manager: Any | None = None
+ self._file_source_instances_manager: Any | None = None
+ self._pages_service: Any | None = None
def _encode_id(self, value: int) -> str:
return self.trans.security.encode_id(value)
@@ -395,14 +394,14 @@ class AgentOperationsManager:
def get_history_graph(
self,
history_id: str,
- seed_src: Optional[str] = None,
- seed_id: Optional[str] = None,
+ seed_src: str | None = None,
+ seed_id: str | None = None,
direction: Literal["backward", "forward", "both"] = "both",
depth: int = 5,
limit: int = 200,
include_deleted: bool = False,
- seed_scope_src: Optional[str] = None,
- seed_scope_id: Optional[str] = None,
+ seed_scope_src: str | None = None,
+ seed_scope_id: str | None = None,
) -> dict[str, Any]:
decoded_history_id = self.trans.security.decode_id(history_id)
response = self.histories_service.graph(
@@ -966,8 +965,7 @@ class AgentOperationsManager:
)
missing_tools: list[str] = []
- latest = stored_workflow.latest_workflow
- if latest is not None:
+ if (latest := stored_workflow.latest_workflow) is not None:
toolbox = self.app.toolbox
seen: set[str] = set()
for tool in contents_manager.get_all_tools(latest):
@@ -1116,8 +1114,8 @@ class AgentOperationsManager:
def list_pages(
self,
- history_id: Optional[str] = None,
- search: Optional[str] = None,
+ history_id: str | None = None,
+ search: str | None = None,
limit: int = 100,
offset: int = 0,
show_published: bool = False,
@@ -1160,11 +1158,11 @@ class AgentOperationsManager:
def create_page(
self,
- history_id: Optional[str] = None,
- title: Optional[str] = None,
- content: Optional[str] = None,
- annotation: Optional[str] = None,
- slug: Optional[str] = None,
+ history_id: str | None = None,
+ title: str | None = None,
+ content: str | None = None,
+ annotation: str | None = None,
+ slug: str | None = None,
) -> dict[str, Any]:
"""Create a markdown page. Attach it to a history (notebook) by passing history_id.
@@ -1184,8 +1182,8 @@ class AgentOperationsManager:
def update_page(
self,
page_id: str,
- content: Optional[str] = None,
- title: Optional[str] = None,
+ content: str | None = None,
+ title: str | None = None,
) -> dict[str, Any]:
"""Update a page. Supplying content creates a new revision tagged edit_source=agent."""
decoded_page_id = self.trans.security.decode_id(page_id)
diff --git a/lib/galaxy/agents/orchestrator.py b/lib/galaxy/agents/orchestrator.py
index 78c759b5ef6..b09635f3302 100644
--- a/lib/galaxy/agents/orchestrator.py
+++ b/lib/galaxy/agents/orchestrator.py
@@ -8,7 +8,6 @@ import re
from pathlib import Path
from typing import (
Any,
- Optional,
)
from pydantic import BaseModel
@@ -102,7 +101,7 @@ class WorkflowOrchestratorAgent(BaseGalaxyAgent):
return normalized
- async def process(self, query: str, context: Optional[dict[str, Any]] = None) -> AgentResponse:
+ async def process(self, query: str, context: dict[str, Any] | None = None) -> AgentResponse:
validation_error = self._validate_query(query)
if validation_error:
return self._validation_error_response(validation_error)
@@ -192,7 +191,7 @@ class WorkflowOrchestratorAgent(BaseGalaxyAgent):
return self._get_agent_config("agent_timeout", 120.0)
async def _execute_sequential(
- self, agents: list[str], query: str, context: Optional[dict[str, Any]] = None
+ self, agents: list[str], query: str, context: dict[str, Any] | None = None
) -> dict[str, AgentResponse]:
"""Execute agents sequentially with timeout protection."""
responses: dict[str, AgentResponse] = {}
@@ -226,7 +225,7 @@ class WorkflowOrchestratorAgent(BaseGalaxyAgent):
return responses
async def _execute_parallel(
- self, agents: list[str], query: str, context: Optional[dict[str, Any]] = None
+ self, agents: list[str], query: str, context: dict[str, Any] | None = None
) -> dict[str, AgentResponse]:
"""Execute agents in parallel with timeout protection."""
log.info(f"Orchestrator: Running agents in PARALLEL mode: {agents}")
diff --git a/lib/galaxy/agents/page_assistant.py b/lib/galaxy/agents/page_assistant.py
index 567257250d1..2a5a74e3a8c 100644
--- a/lib/galaxy/agents/page_assistant.py
+++ b/lib/galaxy/agents/page_assistant.py
@@ -10,7 +10,6 @@ from pathlib import Path
from typing import (
Any,
Literal,
- Optional,
)
from pydantic import (
@@ -168,8 +167,8 @@ class PageAssistantAgent(BaseGalaxyAgent):
agent_type = AgentType.PAGE_ASSISTANT
- def __init__(self, deps: GalaxyAgentDependencies, history_id: Optional[int] = None, page_content: str = ""):
- self.history_id: Optional[int] = history_id
+ def __init__(self, deps: GalaxyAgentDependencies, history_id: int | None = None, page_content: str = ""):
+ self.history_id: int | None = history_id
self.history_is_session: bool = False
self.page_content: str = page_content
super().__init__(deps)
@@ -333,7 +332,7 @@ class PageAssistantAgent(BaseGalaxyAgent):
)
return prompt
- async def process(self, query: str, context: Optional[dict[str, Any]] = None) -> AgentResponse:
+ async def process(self, query: str, context: dict[str, Any] | None = None) -> AgentResponse:
"""Process a page editing or history question."""
capability_error = self._validate_model_capabilities()
if capability_error:
diff --git a/lib/galaxy/agents/registry.py b/lib/galaxy/agents/registry.py
index 4ebaca2e127..df8c9975744 100644
--- a/lib/galaxy/agents/registry.py
+++ b/lib/galaxy/agents/registry.py
@@ -3,9 +3,6 @@ Agent registry for managing available AI agents.
"""
import logging
-from typing import (
- Optional,
-)
from .base import (
BaseGalaxyAgent,
@@ -26,7 +23,7 @@ class AgentRegistry:
self,
agent_type: str,
agent_class: type[BaseGalaxyAgent],
- metadata: Optional[dict] = None,
+ metadata: dict | None = None,
):
if not issubclass(agent_class, BaseGalaxyAgent):
raise ValueError(f"Agent class must inherit from BaseGalaxyAgent: {agent_class}")
@@ -65,7 +62,7 @@ class AgentRegistry:
def get_agent_metadata(self, agent_type: str) -> dict:
return self._agent_metadata.get(agent_type, {})
- def get_capability_blurb(self, agent_type: str) -> Optional[str]:
+ def get_capability_blurb(self, agent_type: str) -> str | None:
"""Return the agent's user-facing capability blurb, or None.
Returns None when the agent type is not registered (e.g. disabled in this
diff --git a/lib/galaxy/agents/router.py b/lib/galaxy/agents/router.py
index a5a3c3ad001..185ebd98bf4 100644
--- a/lib/galaxy/agents/router.py
+++ b/lib/galaxy/agents/router.py
@@ -20,7 +20,6 @@ from functools import partial
from pathlib import Path
from typing import (
Any,
- Optional,
)
import anyio
@@ -49,7 +48,7 @@ class QueryRouterAgent(BaseGalaxyAgent):
"""Router that answers queries directly or delegates to specialist agents."""
agent_type = AgentType.ROUTER
- _handoff_context: Optional[dict[str, Any]] = None
+ _handoff_context: dict[str, Any] | None = None
# The current message drives routing, plus the most recent conversation turn(s) so an
# elliptical follow-up ("what about a workflow for this?", or the answer to a clarifying
@@ -491,7 +490,7 @@ class QueryRouterAgent(BaseGalaxyAgent):
async def ask_for_clarification(
ctx: RunContext[GalaxyAgentDependencies],
question: str,
- options: Optional[list[str]] = None,
+ options: list[str] | None = None,
) -> str:
"""Ask the user ONE concise clarifying question when the request is too ambiguous
or underspecified to route or answer confidently.
@@ -524,7 +523,7 @@ class QueryRouterAgent(BaseGalaxyAgent):
return [i for i, message in enumerate(full_history) if _is_turn_start(message)]
- def _routing_history(self, full_history: Optional[list]) -> Optional[list]:
+ def _routing_history(self, full_history: list | None) -> list | None:
"""The most recent ``ROUTING_HISTORY_TURNS`` turn(s) of ``full_history``, or None when
capped to 0 or there's no history. See ``ROUTING_HISTORY_TURNS`` for the rationale."""
if not full_history or self.ROUTING_HISTORY_TURNS <= 0:
@@ -536,7 +535,7 @@ class QueryRouterAgent(BaseGalaxyAgent):
return full_history[turn_starts[-self.ROUTING_HISTORY_TURNS] :]
return full_history
- async def process(self, query: str, context: Optional[dict[str, Any]] = None) -> AgentResponse:
+ async def process(self, query: str, context: dict[str, Any] | None = None) -> AgentResponse:
validation_error = self._validate_query(query)
if validation_error:
return self._validation_error_response(validation_error)
@@ -601,7 +600,7 @@ class QueryRouterAgent(BaseGalaxyAgent):
log.warning(f"Router agent error, using fallback: {e}")
return self._handle_fallback(query, context, str(e))
- def _handle_fallback(self, query: str, context: Optional[dict[str, Any]], error_msg: str) -> AgentResponse:
+ def _handle_fallback(self, query: str, context: dict[str, Any] | None, error_msg: str) -> AgentResponse:
query_lower = query.lower()
# Citation requests can be answered without AI
diff --git a/lib/galaxy/agents/static_backend.py b/lib/galaxy/agents/static_backend.py
index 7546d17f33a..4fc3cbe9b35 100644
--- a/lib/galaxy/agents/static_backend.py
+++ b/lib/galaxy/agents/static_backend.py
@@ -7,7 +7,6 @@ from YAML rules. Swap at the DI container level — no mocks, no pydantic-ai.
import re
from typing import (
Any,
- Optional,
)
import yaml
@@ -49,13 +48,13 @@ class StaticAgent(BaseGalaxyAgent):
def get_system_prompt(self) -> str:
return ""
- async def process(self, query: str, context: Optional[dict[str, Any]] = None) -> AgentResponse:
+ async def process(self, query: str, context: dict[str, Any] | None = None) -> AgentResponse:
for rule in self._rules:
if self._rule_matches(rule.get("match", {}), query, context):
return self._make_response(rule["response"])
return self._make_response(self._fallback)
- def _rule_matches(self, match: dict[str, Any], query: str, context: Optional[dict[str, Any]]) -> bool:
+ def _rule_matches(self, match: dict[str, Any], query: str, context: dict[str, Any] | None) -> bool:
if "agent_type" in match and match["agent_type"] != self.agent_type:
return False
if "query" in match and not re.search(match["query"], query):
diff --git a/lib/galaxy/agents/tools.py b/lib/galaxy/agents/tools.py
index 8ad989c5c8f..2daf5b23f63 100644
--- a/lib/galaxy/agents/tools.py
+++ b/lib/galaxy/agents/tools.py
@@ -13,7 +13,6 @@ import re
from pathlib import Path
from typing import (
Any,
- Optional,
)
from pydantic import (
@@ -45,7 +44,7 @@ def _iwc_search(query: str, limit: int) -> list[dict[str, Any]]:
return iwc.search_workflows(workflows, query, limit=limit)
-def _iwc_details(trs_id: str) -> Optional[dict[str, Any]]:
+def _iwc_details(trs_id: str) -> dict[str, Any] | None:
workflows = iwc.all_workflows(iwc.fetch_manifest())
for wf in workflows:
if wf.get("trsID") == trs_id:
@@ -59,7 +58,7 @@ class SimplifiedToolRecommendationResult(BaseModel):
primary_tools: list[dict[str, Any]] = []
alternative_tools: list[dict[str, Any]] = []
recommended_workflows: list[dict[str, Any]] = []
- workflow_suggestion: Optional[str] = None
+ workflow_suggestion: str | None = None
parameter_guidance: dict[str, Any] = {}
confidence: ConfidenceLiteral
reasoning: str
@@ -95,7 +94,7 @@ class ToolRecommendationAgent(BaseGalaxyAgent):
super().__init__(deps)
self._tool_calls = 0
- def _charge_tool_budget(self) -> Optional[str]:
+ def _charge_tool_budget(self) -> str | None:
"""Count a data-gathering tool call; once over budget return a stop
message instead of more data so the model recommends from what it has."""
self._tool_calls += 1
@@ -323,7 +322,7 @@ class ToolRecommendationAgent(BaseGalaxyAgent):
log.warning(f"IWC search failed for query={query!r}: {e}")
return []
- async def get_iwc_workflow_details(self, trs_id: str) -> Optional[dict[str, Any]]:
+ async def get_iwc_workflow_details(self, trs_id: str) -> dict[str, Any] | None:
"""Fetch one workflow from the IWC manifest, fully enriched."""
try:
return await asyncio.to_thread(_iwc_details, trs_id)
@@ -348,7 +347,7 @@ class ToolRecommendationAgent(BaseGalaxyAgent):
log.warning(f"Error getting tool categories: {e}")
return []
- async def process(self, query: str, context: Optional[dict[str, Any]] = None) -> AgentResponse:
+ async def process(self, query: str, context: dict[str, Any] | None = None) -> AgentResponse:
validation_error = self._validate_query(query)
if validation_error:
return self._validation_error_response(validation_error)
diff --git a/lib/galaxy/agents/workflow_report.py b/lib/galaxy/agents/workflow_report.py
index 0066cadfc57..9f053c46a45 100644
--- a/lib/galaxy/agents/workflow_report.py
+++ b/lib/galaxy/agents/workflow_report.py
@@ -87,8 +87,7 @@ class WorkflowReportAgent(SimpleGalaxyAgent):
# Workflow outputs — include the originating step label and tool_id so the LLM
# can infer the likely output type (image, tabular, HTML) for directive selection
- outputs = list(workflow.workflow_outputs)
- if outputs:
+ if outputs := list(workflow.workflow_outputs):
lines.append("\nWorkflow outputs (usable in output= directives):")
for out in outputs:
out_label = out.label or out.output_name
diff --git a/lib/galaxy/app/__init__.py b/lib/galaxy/app/__init__.py
index 4033dc0b2ca..8a575adb737 100644
--- a/lib/galaxy/app/__init__.py
+++ b/lib/galaxy/app/__init__.py
@@ -9,7 +9,6 @@ import time
from collections.abc import Callable
from typing import (
Any,
- Optional,
)
from beaker.cache import CacheManager
@@ -296,8 +295,8 @@ class MinimalGalaxyApplication(BasicSharedApp, HaltableContainer, SentryClientMi
container_finder: containers.ContainerFinder
install_model: ModelMapping
object_store: BaseObjectStore
- _tool_data_tables: Optional[BaseToolDataTableManager]
- _genome_builds: Optional[GenomeBuilds]
+ _tool_data_tables: BaseToolDataTableManager | None
+ _genome_builds: GenomeBuilds | None
def __init__(self, fsmon=False, **kwargs) -> None:
super().__init__()
@@ -344,7 +343,7 @@ class MinimalGalaxyApplication(BasicSharedApp, HaltableContainer, SentryClientMi
if self.config.fluent_log:
from galaxy.util.custom_logging.fluent_log import FluentTraceLogger
- self.trace_logger: Optional[FluentTraceLogger] = FluentTraceLogger(
+ self.trace_logger: FluentTraceLogger | None = FluentTraceLogger(
"galaxy", self.config.fluent_host, self.config.fluent_port
)
else:
@@ -613,7 +612,7 @@ class MinimalGalaxyApplication(BasicSharedApp, HaltableContainer, SentryClientMi
time.sleep(pause)
@property
- def tool_dependency_dir(self) -> Optional[str]:
+ def tool_dependency_dir(self) -> str | None:
return self.toolbox.dependency_manager.default_base_path
def _shutdown_object_store(self):
@@ -990,7 +989,7 @@ class UniverseApplication(StructuredApp, GalaxyManagerApplication, InstallationT
# but monitor only runs on workflow scheduler processes)
self.workflow_completion_manager = WorkflowCompletionManager(self)
self.workflow_completion_hook_registry = WorkflowCompletionHookRegistry(self)
- self.workflow_completion_monitor: Optional[WorkflowCompletionMonitor] = None
+ self.workflow_completion_monitor: WorkflowCompletionMonitor | None = None
if self.workflow_scheduling_manager._is_workflow_handler():
self.workflow_completion_monitor = WorkflowCompletionMonitor(
self,
@@ -1039,7 +1038,7 @@ class UniverseApplication(StructuredApp, GalaxyManagerApplication, InstallationT
# only when statsd is actually configured (a non-None client) and the
# shared queue_metrics_interval cadence is enabled. The server_name is
# read post-fork so each worker tags its own series.
- self.sse_connection_gauge_emitter: Optional[SSEConnectionGaugeEmitter] = None
+ self.sse_connection_gauge_emitter: SSEConnectionGaugeEmitter | None = None
statsd_client = self.execution_timer_factory.galaxy_statsd_client
if (
statsd_client is not None
@@ -1132,7 +1131,7 @@ class ExecutionTimerFactory:
if statsd_host := getattr(config, "statsd_host", None):
from galaxy.web.statsd_client import GalaxyStatsdClient
- self.galaxy_statsd_client: Optional[GalaxyStatsdClient] = GalaxyStatsdClient(
+ self.galaxy_statsd_client: GalaxyStatsdClient | None = GalaxyStatsdClient(
statsd_host,
getattr(config, "statsd_port", 8125),
getattr(config, "statsd_prefix", "galaxy"),
diff --git a/lib/galaxy/app_unittest_utils/galaxy_mock.py b/lib/galaxy/app_unittest_utils/galaxy_mock.py
index c5ff08990f8..89575823f38 100644
--- a/lib/galaxy/app_unittest_utils/galaxy_mock.py
+++ b/lib/galaxy/app_unittest_utils/galaxy_mock.py
@@ -12,7 +12,6 @@ from collections.abc import (
from typing import (
Any,
cast,
- Optional,
)
import mako
@@ -112,7 +111,7 @@ def buildMockEnviron(**kwargs):
class MockApp(di.Container, GalaxyDataTestApp):
config: "MockAppConfig"
amqp_type: str
- job_search: Optional[JobSearch] = None
+ job_search: JobSearch | None = None
_toolbox: ToolBox
tool_cache: ToolCache
install_model: ModelMapping
@@ -122,7 +121,7 @@ class MockApp(di.Container, GalaxyDataTestApp):
workflow_manager: WorkflowsManager
history_manager: HistoryManager
job_metrics: JobMetrics
- vault: Optional[Vault] = None
+ vault: Vault | None = None
execution_timer_factory: Any
stop: bool
is_webapp: bool = True
@@ -429,7 +428,6 @@ class MockTrans:
class MockVisualizationsRegistry:
-
def get_visualizations(self, trans, target):
return []
diff --git a/lib/galaxy/app_unittest_utils/toolbox_support.py b/lib/galaxy/app_unittest_utils/toolbox_support.py
index 65a8340c920..164b81152c3 100644
--- a/lib/galaxy/app_unittest_utils/toolbox_support.py
+++ b/lib/galaxy/app_unittest_utils/toolbox_support.py
@@ -3,7 +3,6 @@ import json
import logging
import os
import string
-from typing import Optional
from galaxy.app_unittest_utils.tools_support import UsesTools
from galaxy.config_watchers import ConfigWatchers
@@ -55,7 +54,7 @@ class SimplifiedToolBox(ToolBox):
class BaseToolBoxTestCase(TestCase, UsesTools):
- _toolbox: Optional[SimplifiedToolBox] = None
+ _toolbox: SimplifiedToolBox | None = None
@property
def integrated_tool_panel_path(self):
diff --git a/lib/galaxy/app_unittest_utils/tools_support.py b/lib/galaxy/app_unittest_utils/tools_support.py
index 7528bfddb27..8fa8e431332 100644
--- a/lib/galaxy/app_unittest_utils/tools_support.py
+++ b/lib/galaxy/app_unittest_utils/tools_support.py
@@ -10,7 +10,6 @@ import tempfile
from collections import defaultdict
from typing import (
cast,
- Optional,
)
import galaxy.datatypes.registry
@@ -78,7 +77,7 @@ class MockActionI:
class UsesTools(UsesApp):
- tool_action: Optional[MockActionI] = None
+ tool_action: MockActionI | None = None
def _init_tool(
self,
@@ -89,7 +88,7 @@ class UsesTools(UsesApp):
tool_id="test_tool",
extra_file_contents=None,
extra_file_path=None,
- tool_path: Optional[StrPath] = None,
+ tool_path: StrPath | None = None,
):
if tool_path is None:
self.tool_file: StrPath = os.path.join(self.test_directory, filename)
diff --git a/lib/galaxy/authnz/managers.py b/lib/galaxy/authnz/managers.py
index 7e2c3eca1b4..1de6c3a6bcd 100644
--- a/lib/galaxy/authnz/managers.py
+++ b/lib/galaxy/authnz/managers.py
@@ -3,7 +3,6 @@ from __future__ import annotations
import builtins
import logging
from typing import (
- Optional,
TYPE_CHECKING,
TypedDict,
)
@@ -347,9 +346,7 @@ class AuthnzManager:
log.warning(f"An error occurred when refreshing user token: {e}")
return {"refreshed": False, "reauthentication_required": False}
- def refresh_expiring_oidc_tokens(
- self, trans: GalaxyWebTransaction, user: Optional[model.User] = None
- ) -> str | None:
+ def refresh_expiring_oidc_tokens(self, trans: GalaxyWebTransaction, user: model.User | None = None) -> str | None:
"""
Refresh expiring OIDC tokens for all providers associated with a user.
diff --git a/lib/galaxy/celery/__init__.py b/lib/galaxy/celery/__init__.py
index 127f4b641b0..53a7c036599 100644
--- a/lib/galaxy/celery/__init__.py
+++ b/lib/galaxy/celery/__init__.py
@@ -93,8 +93,7 @@ class GalaxyTask(Task):
"""
if status == "RETRY":
return # Don't clean up on retry — the task will run again
- app = get_galaxy_app()
- if app:
+ if app := get_galaxy_app():
app[GalaxyTaskAfterReturn](self, task_id, args, kwargs)
diff --git a/lib/galaxy/celery/base_task.py b/lib/galaxy/celery/base_task.py
index 4520c20c227..80a901871b7 100644
--- a/lib/galaxy/celery/base_task.py
+++ b/lib/galaxy/celery/base_task.py
@@ -89,9 +89,8 @@ class GalaxyTaskBeforeStartUserRateLimit(GalaxyTaskBeforeStart):
# Check if this task already has a reserved timeslot from a previous attempt
headers = task.request.headers or {}
- reserved_time_str = headers.get(HEADER_SCHEDULED_TIME)
- if reserved_time_str:
+ if reserved_time_str := headers.get(HEADER_SCHEDULED_TIME):
# Retry path: verify we've reached our reserved timeslot
reserved_time = datetime.datetime.fromisoformat(reserved_time_str)
if now >= reserved_time:
diff --git a/lib/galaxy/celery/tasks.py b/lib/galaxy/celery/tasks.py
index 59c9c3ed721..c7190a04d0f 100644
--- a/lib/galaxy/celery/tasks.py
+++ b/lib/galaxy/celery/tasks.py
@@ -7,7 +7,6 @@ from functools import lru_cache
from pathlib import Path
from typing import (
Any,
- Optional,
)
from urllib.parse import urlparse
@@ -105,8 +104,8 @@ def cached_create_tool_from_representation(
app: MinimalManagerApp,
raw_tool_source: str,
tool_source_class: TOOL_SOURCE_CLASS,
- tool_dir: Optional[str] = None,
- tool_id: Optional[str] = None,
+ tool_dir: str | None = None,
+ tool_id: str | None = None,
):
return create_tool_from_representation(
app=app,
@@ -119,7 +118,7 @@ def cached_create_tool_from_representation(
@galaxy_task(action="recalculate a user's disk usage")
def recalculate_user_disk_usage(
- session: galaxy_scoped_session, object_store: BaseObjectStore, task_user_id: Optional[int] = None
+ session: galaxy_scoped_session, object_store: BaseObjectStore, task_user_id: int | None = None
):
if task_user_id:
user = session.get(User, task_user_id)
@@ -133,16 +132,14 @@ def recalculate_user_disk_usage(
@galaxy_task(ignore_result=True, action="purge a history dataset")
def purge_hda(
- hda_manager: HDAManager, hda_id: int, task_user_id: Optional[int] = None, preserve_owner_update_time: bool = False
+ hda_manager: HDAManager, hda_id: int, task_user_id: int | None = None, preserve_owner_update_time: bool = False
):
hda = hda_manager.by_id(hda_id)
hda_manager._purge(hda, preserve_owner_update_time=preserve_owner_update_time)
@galaxy_task(ignore_result=True, action="completely removes a set of datasets from the object_store")
-def purge_datasets(
- dataset_manager: DatasetManager, request: PurgeDatasetsTaskRequest, task_user_id: Optional[int] = None
-):
+def purge_datasets(dataset_manager: DatasetManager, request: PurgeDatasetsTaskRequest, task_user_id: int | None = None):
dataset_manager.purge_datasets(request)
@@ -152,7 +149,7 @@ def purge_history_datasets(
dataset_manager: DatasetManager,
object_store: BaseObjectStore,
request: PurgeHistoryDatasetsTaskRequest,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
"""Batch purge all HDAs in a history in a single task.
@@ -202,8 +199,7 @@ def purge_history_datasets(
)
sa_session.commit()
# Recalculate user disk usage from scratch
- user = history.user
- if user:
+ if user := history.user:
user.calculate_and_set_disk_usage(object_store)
if not request.preserve_owner_update_time:
user.update_time = now()
@@ -217,7 +213,7 @@ def materialize(
hda_manager: HDAManager,
request: MaterializeDatasetInstanceTaskRequest,
sa_session: galaxy_scoped_session,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
"""Materialize datasets using HDAManager."""
hda_manager.materialize(request, sa_session())
@@ -229,7 +225,7 @@ def set_job_metadata(
extended_metadata_collection: bool,
job_id: int,
sa_session: galaxy_scoped_session,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
) -> None:
return abort_when_job_stops(
set_metadata_portable,
@@ -249,7 +245,7 @@ def change_datatype(
dataset_id: int,
datatype: str,
model_class: str = "HistoryDatasetAssociation",
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
manager = _get_dataset_manager(hda_manager, ldda_manager, model_class)
dataset_instance = manager.by_id(dataset_id)
@@ -270,7 +266,7 @@ def touch(
sa_session: galaxy_scoped_session,
item_id: int,
model_class: str = "HistoryDatasetCollectionAssociation",
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
if model_class != "HistoryDatasetCollectionAssociation":
raise NotImplementedError(f"touch method not implemented for '{model_class}'")
@@ -289,7 +285,7 @@ def set_metadata(
model_class: str = "HistoryDatasetAssociation",
overwrite: bool = True,
ensure_can_set_metadata: bool = True,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
"""
ensure_can_set_metadata can be bypassed for new outputs.
@@ -322,7 +318,7 @@ def bulk_move_storage(
app: MinimalManagerApp,
run_db_id: int,
task_user_id: int,
- notify_on_completion: Optional[bool] = None,
+ notify_on_completion: bool | None = None,
):
run = sa_session.get(DatasetStorageOperationRun, run_db_id)
if run is None:
@@ -410,7 +406,7 @@ def setup_fetch_data(
tool_source_class: TOOL_SOURCE_CLASS,
app: MinimalManagerApp,
sa_session: galaxy_scoped_session,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
tool = cached_create_tool_from_representation(
app=app, raw_tool_source=raw_tool_source, tool_source_class=tool_source_class
@@ -451,7 +447,7 @@ def finish_job(
tool_source_class: TOOL_SOURCE_CLASS,
app: MinimalManagerApp,
sa_session: galaxy_scoped_session,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
tool = cached_create_tool_from_representation(
app=app, raw_tool_source=raw_tool_source, tool_source_class=tool_source_class
@@ -517,8 +513,8 @@ def fetch_data(
job_id: int,
app: MinimalManagerApp,
sa_session: galaxy_scoped_session,
- task_user_id: Optional[int] = None,
-) -> Optional[str]:
+ task_user_id: int | None = None,
+) -> str | None:
if setup_return is None:
return None
job = sa_session.get(Job, job_id)
@@ -550,7 +546,7 @@ def queue_jobs(request: QueueJobs, app: MinimalManagerApp, job_submitter: JobSub
def export_history(
model_store_manager: ModelStoreManager,
request: SetupHistoryExportJob,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
model_store_manager.setup_history_export_job(request)
@@ -559,7 +555,7 @@ def export_history(
def prepare_dataset_collection_download(
request: PrepareDatasetCollectionDownload,
collection_manager: DatasetCollectionManager,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
"""Create a short term storage file tracked and available for download of target collection."""
collection_manager.write_dataset_collection(request)
@@ -570,7 +566,7 @@ def prepare_pdf_download(
request: GeneratePdfDownload,
config: GalaxyAppConfiguration,
short_term_storage_monitor: ShortTermStorageMonitor,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
"""Create a short term storage file tracked and available for download of target PDF for Galaxy Markdown."""
generate_branded_pdf(request, config, short_term_storage_monitor)
@@ -580,7 +576,7 @@ def prepare_pdf_download(
def prepare_history_download(
model_store_manager: ModelStoreManager,
request: GenerateHistoryDownload,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
model_store_manager.prepare_history_download(request)
@@ -589,7 +585,7 @@ def prepare_history_download(
def prepare_history_content_download(
model_store_manager: ModelStoreManager,
request: GenerateHistoryContentDownload,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
model_store_manager.prepare_history_content_download(request)
@@ -598,7 +594,7 @@ def prepare_history_content_download(
def prepare_invocation_download(
model_store_manager: ModelStoreManager,
request: GenerateInvocationDownload,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
model_store_manager.prepare_invocation_download(request)
@@ -607,7 +603,7 @@ def prepare_invocation_download(
def write_invocation_to(
model_store_manager: ModelStoreManager,
request: WriteInvocationTo,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
model_store_manager.write_invocation_to(request)
@@ -616,7 +612,7 @@ def write_invocation_to(
def write_history_to(
model_store_manager: ModelStoreManager,
request: WriteHistoryTo,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
model_store_manager.write_history_to(request)
@@ -625,7 +621,7 @@ def write_history_to(
def write_history_content_to(
model_store_manager: ModelStoreManager,
request: WriteHistoryContentTo,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
model_store_manager.write_history_content_to(request)
@@ -634,7 +630,7 @@ def write_history_content_to(
def import_model_store(
model_store_manager: ModelStoreManager,
request: ImportModelStoreTaskRequest,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
model_store_manager.import_model_store(request)
@@ -643,7 +639,7 @@ def import_model_store(
def compute_dataset_hash(
dataset_manager: DatasetManager,
request: ComputeDatasetHashTaskRequest,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
dataset_manager.compute_hash(request)
@@ -656,10 +652,10 @@ def import_data_bundle(
tool_data_import_manager: ToolDataImportManager,
config: GalaxyAppConfiguration,
src: str,
- uri: Optional[str] = None,
- id: Optional[int] = None,
- tool_data_file_path: Optional[str] = None,
- task_user_id: Optional[int] = None,
+ uri: str | None = None,
+ id: int | None = None,
+ tool_data_file_path: str | None = None,
+ task_user_id: int | None = None,
):
if src == "uri":
assert uri
diff --git a/lib/galaxy/config/__init__.py b/lib/galaxy/config/__init__.py
index ace3236d531..8d0b78f7628 100644
--- a/lib/galaxy/config/__init__.py
+++ b/lib/galaxy/config/__init__.py
@@ -26,7 +26,6 @@ from typing import (
SupportsInt,
TYPE_CHECKING,
TypeVar,
- Union,
)
from urllib.parse import urlparse
@@ -256,7 +255,7 @@ OptStr = TypeVar("OptStr", None, str)
class BaseAppConfiguration(HasDynamicProperties):
# Override in subclasses (optional): {KEY: config option, VALUE: deprecated directory name}
# If VALUE == first directory in a user-supplied path that resolves to KEY, it will be stripped from that path
- renamed_options: Optional[dict[str, str]] = None
+ renamed_options: dict[str, str] | None = None
deprecated_dirs: dict[str, str] = {}
paths_to_check_against_root: set[str] = (
set()
@@ -462,7 +461,7 @@ class BaseAppConfiguration(HasDynamicProperties):
return path
def _update_raw_config_from_kwargs(self, kwargs):
- type_converters: dict[str, Callable[[Any], Union[bool, int, float, str]]] = {
+ type_converters: dict[str, Callable[[Any], bool | int | float | str]] = {
"bool": string_as_bool,
"int": int,
"float": float,
@@ -626,7 +625,7 @@ class BaseAppConfiguration(HasDynamicProperties):
class CommonConfigurationMixin:
"""Shared configuration settings code for Galaxy and ToolShed."""
- sentry_dsn: Optional[str]
+ sentry_dsn: str | None
config_dict: dict[str, str]
@property
@@ -743,7 +742,7 @@ class GalaxyAppConfiguration(GalaxyAppConfigurationAttributes, BaseAppConfigurat
container_resolvers_config_file: str
database_connection: str
drmaa_external_runjob_script: str
- email_from: Optional[str]
+ email_from: str | None
enable_tool_shed_check: bool
file_source_temp_dir: str
galaxy_data_manager_data_path: str
@@ -1520,7 +1519,7 @@ def get_database_engine_options(kwargs, model_prefix=""):
Allow options for the SQLAlchemy database engine to be passed by using
the prefix "database_engine_option".
"""
- conversions: dict[str, Callable[[Any], Union[bool, int]]] = {
+ conversions: dict[str, Callable[[Any], bool | int]] = {
"convert_unicode": string_as_bool,
"pool_timeout": int,
"echo": string_as_bool,
diff --git a/lib/galaxy/config/config_manage.py b/lib/galaxy/config/config_manage.py
index ed05f124143..b8084860b80 100644
--- a/lib/galaxy/config/config_manage.py
+++ b/lib/galaxy/config/config_manage.py
@@ -13,7 +13,6 @@ from textwrap import TextWrapper
from typing import (
Any,
NamedTuple,
- Optional,
)
import yaml
@@ -239,7 +238,7 @@ REPORTS_APP = App(
APPS = {"galaxy": GALAXY_APP, "tool_shed": SHED_APP, "reports": REPORTS_APP}
-def main(argv: Optional[list[str]] = None) -> None:
+def main(argv: list[str] | None = None) -> None:
"""Entry point for conversion process."""
if argv is None:
argv = sys.argv[1:]
diff --git a/lib/galaxy/config/url_headers.py b/lib/galaxy/config/url_headers.py
index 908999f4abf..47efdb52339 100644
--- a/lib/galaxy/config/url_headers.py
+++ b/lib/galaxy/config/url_headers.py
@@ -1,7 +1,6 @@
import abc
import logging
import re
-from typing import Optional
import yaml
from pydantic import (
@@ -144,7 +143,7 @@ class UrlHeadersConfiguration(UrlHeadersConfig):
def _find_header_in_patterns(
self, header_name: str, matching_patterns: list[UrlPatternConfig]
- ) -> Optional[tuple[HeaderConfig, UrlPatternConfig]]:
+ ) -> tuple[HeaderConfig, UrlPatternConfig] | None:
"""
Find a header configuration in matching patterns.
diff --git a/lib/galaxy/datatypes/_schema.py b/lib/galaxy/datatypes/_schema.py
index f3e8780b482..b976f515e26 100644
--- a/lib/galaxy/datatypes/_schema.py
+++ b/lib/galaxy/datatypes/_schema.py
@@ -1,7 +1,3 @@
-from typing import (
- Optional,
-)
-
from pydantic import (
BaseModel,
Field,
@@ -26,12 +22,11 @@ __all__ = [
class CompositeFileInfo(BaseModel):
name: str = Field(..., title="Name", description="The name of this composite file") # Mark this field as required
optional: bool = Field(title="Optional", description="") # TODO add description
- mimetype: Optional[str] = Field(title="MIME type", description="The MIME type of this file")
- description: Optional[str] = Field(
- title="Description", description="Summary description of the purpouse of this file"
- )
- substitute_name_with_metadata: Optional[str] = Field(
- title="Substitute name with metadata", description="" # TODO add description
+ mimetype: str | None = Field(title="MIME type", description="The MIME type of this file")
+ description: str | None = Field(title="Description", description="Summary description of the purpouse of this file")
+ substitute_name_with_metadata: str | None = Field(
+ title="Substitute name with metadata",
+ description="", # TODO add description
)
is_binary: bool = Field(title="Is binary", description="Whether this file is a binary file")
to_posix_lines: bool = Field(title="To posix lines", description="") # TODO add description
@@ -45,8 +40,8 @@ class DatatypeDetails(BaseModel):
description="The data type’s Dataset file extension",
examples=["bed"],
)
- description: Optional[str] = Field(title="Description", description="A summary description for this data type")
- description_url: Optional[HttpUrl] = Field(
+ description: str | None = Field(title="Description", description="A summary description for this data type")
+ description_url: HttpUrl | None = Field(
title="Description URL",
description="The URL to a detailed description for this datatype",
examples=["https://wiki.galaxyproject.org/Learn/Datatypes#Bed"],
@@ -56,15 +51,15 @@ class DatatypeDetails(BaseModel):
title="Display in upload",
description="If True, the associated file extension will be displayed in the `File Format` select list in the `Upload File from your computer` tool in the `Get Data` tool section of the tool panel",
)
- composite_files: Optional[list[CompositeFileInfo]] = Field(
+ composite_files: list[CompositeFileInfo] | None = Field(
default=None, title="Composite files", description="A collection of files composing this data type"
)
- upload_warning: Optional[str] = Field(
+ upload_warning: str | None = Field(
default=None,
title="Upload warning",
description="End-user information regarding potential pitfalls with this upload type.",
)
- display_behavior: Optional[str] = Field(
+ display_behavior: str | None = Field(
default=None,
title="Display behavior",
description="How this datatype behaves when displayed with preview=True: 'inline' (can be displayed in browser) or 'download' (triggers download)",
@@ -129,12 +124,12 @@ class DatatypeEDAMDetails(BaseModel):
description="The EDAM prefixed Resource Identifier",
examples=["format_1782"],
)
- label: Optional[str] = Field(
+ label: str | None = Field(
title="Label",
description="The EDAM label",
examples=["NCBI gene report format"],
)
- definition: Optional[str] = Field(
+ definition: str | None = Field(
title="Definition",
description="The EDAM definition",
examples=["Entry (gene) format of the NCBI database."],
diff --git a/lib/galaxy/datatypes/anvio.py b/lib/galaxy/datatypes/anvio.py
index e89e3db59ed..86eba2cae96 100644
--- a/lib/galaxy/datatypes/anvio.py
+++ b/lib/galaxy/datatypes/anvio.py
@@ -6,7 +6,6 @@ https://github.com/merenlab/anvio
import glob
import logging
import os
-from typing import Optional
from galaxy.datatypes.metadata import MetadataElement
from galaxy.datatypes.protocols import (
@@ -86,7 +85,7 @@ class AnvioComposite(Html):
class AnvioDB(AnvioComposite):
"""Class for AnvioDB database files."""
- _anvio_basename: Optional[str] = None
+ _anvio_basename: str | None = None
MetadataElement(name="anvio_basename", default=_anvio_basename, desc="Basename", readonly=True)
file_ext = "anvio_db"
diff --git a/lib/galaxy/datatypes/assembly.py b/lib/galaxy/datatypes/assembly.py
index d5cdf5c1074..5c1279563bc 100644
--- a/lib/galaxy/datatypes/assembly.py
+++ b/lib/galaxy/datatypes/assembly.py
@@ -184,7 +184,7 @@ class Velvet(Html):
opt_text = " (optional)"
if composite_file.get("description"):
rval.append(
- f"
{fn} ({composite_file.get('description')}) {opt_text} "
+ f'{fn} ({composite_file.get("description")}) {opt_text} '
)
else:
rval.append(f'{fn} {opt_text} ')
@@ -233,7 +233,7 @@ class Velvet(Html):
opt_text = " (optional)"
if composite_file.get("description"):
rval.append(
- f"{fn} ({composite_file.get('description')}) {opt_text} "
+ f'{fn} ({composite_file.get("description")}) {opt_text} '
)
else:
rval.append(f'{fn} {opt_text} ')
diff --git a/lib/galaxy/datatypes/binary.py b/lib/galaxy/datatypes/binary.py
index f950d0fc84d..60872806c63 100644
--- a/lib/galaxy/datatypes/binary.py
+++ b/lib/galaxy/datatypes/binary.py
@@ -17,9 +17,7 @@ from collections.abc import Iterable
from json import dumps
from typing import (
Any,
- Optional,
TYPE_CHECKING,
- Union,
)
import defusedxml.ElementTree as ET
@@ -504,7 +502,7 @@ class CompressedZarrZipArchive(CompressedZipArchive):
meta_file = self._find_zarr_metadata_file(zf)
return meta_file is not None
- def _find_zarr_metadata_file(self, zip_file: zipfile.ZipFile) -> Optional[str]:
+ def _find_zarr_metadata_file(self, zip_file: zipfile.ZipFile) -> str | None:
"""Returns the path to the metadata file in the Zarr store if found."""
# Depending on the Zarr version, the metadata file can be in different locations
# In v1 the metadata is in a file named "meta" https://zarr-specs.readthedocs.io/en/latest/v1/v1.0.html
@@ -535,7 +533,7 @@ class CompressedOMEZarrZipArchive(CompressedZarrZipArchive):
meta_file = self._find_ome_zarr_metadata_file(zf)
return meta_file is not None
- def _find_ome_zarr_metadata_file(self, zip_file: zipfile.ZipFile) -> Optional[str]:
+ def _find_ome_zarr_metadata_file(self, zip_file: zipfile.ZipFile) -> str | None:
expected_meta_file_name = "OME/METADATA.ome.xml"
for file in zip_file.namelist():
if file.endswith(expected_meta_file_name):
@@ -573,8 +571,8 @@ class _BamOrSam:
]
else:
dataset.metadata.metadata_incomplete = True
- dataset.metadata.sort_order = bam_file.header.get("HD", {}).get("SO", None) # type: ignore [attr-defined]
- dataset.metadata.bam_version = bam_file.header.get("HD", {}).get("VN", None) # type: ignore [attr-defined]
+ dataset.metadata.sort_order = bam_file.header.get("HD", {}).get("SO", None) # type: ignore[attr-defined]
+ dataset.metadata.bam_version = bam_file.header.get("HD", {}).get("VN", None) # type: ignore[attr-defined]
except Exception:
# Per Dan, don't log here because doing so will cause datasets that
# fail metadata to end in the error state
@@ -587,7 +585,7 @@ class BamNative(CompressedArchive, _BamOrSam):
edam_format = "format_2572"
edam_data = "data_0863"
file_ext = "unsorted.bam"
- sort_flag: Optional[str] = None
+ sort_flag: str | None = None
MetadataElement(name="columns", default=12, desc="Number of columns", readonly=True, visible=False, no_value=0)
MetadataElement(
@@ -691,7 +689,7 @@ class BamNative(CompressedArchive, _BamOrSam):
"""
pysam.merge("-O", "BAM", output_file, *split_files)
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
Binary.init_meta(self, dataset, copy_from=copy_from)
def sniff(self, filename: str) -> bool:
@@ -766,7 +764,7 @@ class BamNative(CompressedArchive, _BamOrSam):
# Remove temp file and empty temporary directory
os.rmdir(tmp_dir)
- def get_chunk(self, trans, dataset: HasFileName, offset: int = 0, ck_size: Optional[int] = None) -> str:
+ def get_chunk(self, trans, dataset: HasFileName, offset: int = 0, ck_size: int | None = None) -> str:
if not offset == -1:
try:
with pysam.AlignmentFile(dataset.get_file_name(), "rb", check_sq=False) as bamfile:
@@ -818,10 +816,10 @@ class BamNative(CompressedArchive, _BamOrSam):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
- offset: Optional[int] = None,
- ck_size: Optional[int] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
+ offset: int | None = None,
+ ck_size: int | None = None,
**kwd,
):
headers = kwd.get("headers", {})
@@ -924,7 +922,7 @@ class Bam(BamNative):
return needs_sorting
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
# These metadata values are not accessible by users, always overwrite
super().set_meta(dataset=dataset, overwrite=overwrite, **kwd)
@@ -1111,7 +1109,7 @@ class CRAM(Binary):
)
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
major_version, minor_version = self.get_cram_version(dataset.get_file_name())
if major_version != -1:
@@ -1195,7 +1193,7 @@ class Bcf(BaseBcf):
return False
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
"""Creates the index for the BCF file."""
# These metadata values are not accessible by users, always overwrite
@@ -1594,7 +1592,7 @@ class Anndata(H5):
dataset.metadata.layers_count = len(anndata_file)
dataset.metadata.layers_names = list(anndata_file.keys())
- def get_index_value(tmp: Union[h5py.Dataset, h5py.Datatype, h5py.Group]):
+ def get_index_value(tmp: h5py.Dataset | h5py.Datatype | h5py.Group):
if isinstance(tmp, (h5py.Dataset, h5py.Datatype)):
if "index" in tmp.dtype.names:
return tmp["index"]
@@ -1676,7 +1674,6 @@ class Anndata(H5):
# Resolving the problematic shape parameter
if "X" in dataset.metadata.layers_names:
-
# Check if X is a null/empty matrix (common in fragment-only files of snapatac data for example)
if (
anndata_file["X"].attrs.get("encoding-type") == "null"
@@ -1804,7 +1801,7 @@ class GmxBinary(Binary):
Base class for GROMACS binary files - xtc, trr, cpt
"""
- magic_number: Optional[int] = None # variables to be overwritten in the child class
+ magic_number: int | None = None # variables to be overwritten in the child class
file_ext = ""
def sniff_prefix(self, file_prefix: FilePrefix) -> bool:
@@ -2135,7 +2132,7 @@ class H5MLM(H5):
)
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
try:
spec_key = "hyper_params"
@@ -2218,8 +2215,8 @@ class H5MLM(H5):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
**kwd,
):
headers = kwd.pop("headers", {})
@@ -2517,7 +2514,7 @@ class SQlite(Binary):
file_ext = "sqlite"
edam_format = "format_3621"
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
Binary.init_meta(self, dataset, copy_from=copy_from)
def set_meta(self, dataset: DatasetProtocol, overwrite: bool = True, **kwd) -> None:
@@ -3803,7 +3800,7 @@ class MongoDBArchive(CompressedArchive):
def set_peek(self, dataset: DatasetProtocol, **kwd) -> None:
if not dataset.dataset.purged:
dataset.peek = f"MongoDB Archive ({nice_size(dataset.get_size())})"
- dataset.blurb = f'MongoDB version {dataset.metadata.version or "unknown"}'
+ dataset.blurb = f"MongoDB version {dataset.metadata.version or 'unknown'}"
else:
dataset.peek = "file does not exist"
dataset.blurb = "file purged from disk"
diff --git a/lib/galaxy/datatypes/blast.py b/lib/galaxy/datatypes/blast.py
index 2336e3fdf8f..48556e81f20 100644
--- a/lib/galaxy/datatypes/blast.py
+++ b/lib/galaxy/datatypes/blast.py
@@ -35,9 +35,6 @@ import logging
import os
from collections.abc import Callable
from time import sleep
-from typing import (
- Optional,
-)
from galaxy.datatypes.protocols import (
DatasetHasHidProtocol,
@@ -211,10 +208,10 @@ class _BlastDb(Data):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
- offset: Optional[int] = None,
- ck_size: Optional[int] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
+ offset: int | None = None,
+ ck_size: int | None = None,
**kwd,
):
"""
@@ -260,7 +257,7 @@ class _BlastDb(Data):
raise NotImplementedError("Merging BLAST databases is non-trivial (do this via makeblastdb?)")
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""Split a BLAST database (not implemented for now)."""
if split_params is None:
return None
diff --git a/lib/galaxy/datatypes/constructive_solid_geometry.py b/lib/galaxy/datatypes/constructive_solid_geometry.py
index 69555a0e5d4..68223c3b52f 100644
--- a/lib/galaxy/datatypes/constructive_solid_geometry.py
+++ b/lib/galaxy/datatypes/constructive_solid_geometry.py
@@ -8,7 +8,6 @@ import abc
import logging
import re
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -393,8 +392,8 @@ class Vtk:
return dataset
def set_structure_metadata(
- self, line: str, dataset: DatasetProtocol, dataset_type: Optional[str]
- ) -> tuple[DatasetProtocol, Optional[str]]:
+ self, line: str, dataset: DatasetProtocol, dataset_type: str | None
+ ) -> tuple[DatasetProtocol, str | None]:
"""
The fourth part of legacy VTK files is the dataset structure. The
geometry part describes the geometry and topology of the dataset.
@@ -685,7 +684,7 @@ class NeperPoints(data.Text):
with open(dataset.get_file_name(), errors="ignore") as fh:
dataset.metadata.dimension = self._get_dimension(fh)
- def _get_dimension(self, fh: "TextIOBase", maxlines: int = 100, sep: Optional[str] = None) -> Optional[float]:
+ def _get_dimension(self, fh: "TextIOBase", maxlines: int = 100, sep: str | None = None) -> float | None:
dim = None
try:
for i, line in enumerate(fh):
@@ -1030,14 +1029,12 @@ class GocadSGrid(data.Text):
MetadataElement(name="name", default=None, desc="Grid name", readonly=True, optional=True, visible=True)
def extract_version(self, line: str) -> str:
- match = re.search(r"GOCAD SGrid\s+([\d.]+)", line)
- if match:
+ if match := re.search(r"GOCAD SGrid\s+([\d.]+)", line):
return match.group(1)
return "?"
def extract_name(self, line: str) -> str:
- match = re.search(r"name:\s*(.*)", line)
- if match:
+ if match := re.search(r"name:\s*(.*)", line):
return match.group(1).strip()
return "?"
@@ -1082,8 +1079,7 @@ class FeflowFem(data.Text):
MetadataElement(name="problem_type", default=None, desc="Problem type", readonly=True, optional=True, visible=True)
def extract_version(self, line: str) -> str:
- match = re.search(r"\(([Vv][^)]+)\)", line)
- if match:
+ if match := re.search(r"\(([Vv][^)]+)\)", line):
return match.group(1)
return "?"
diff --git a/lib/galaxy/datatypes/data.py b/lib/galaxy/datatypes/data.py
index 63cb7c5f8e7..96a2c5deff3 100644
--- a/lib/galaxy/datatypes/data.py
+++ b/lib/galaxy/datatypes/data.py
@@ -121,9 +121,7 @@ def validate(dataset_instance: DatasetProtocol) -> DatatypeValidation:
return datatype_validation
-def get_params_and_input_name(
- converter, deps: Optional[dict], target_context: Optional[dict] = None
-) -> tuple[dict, str]:
+def get_params_and_input_name(converter, deps: dict | None, target_context: dict | None = None) -> tuple[dict, str]:
# Generate parameter dictionary
params = {}
# determine input parameter name and add to params
@@ -228,23 +226,23 @@ class Data(metaclass=DataMeta):
supported_display_apps: dict[str, Any] = {}
# The dataset contains binary data --> do not space_to_tab or convert newlines, etc.
# Allow binary file uploads of this type when True.
- is_binary: Union[bool, Literal["maybe"]] = True
+ is_binary: bool | Literal["maybe"] = True
# Composite datatypes
- composite_type: Optional[str] = None
+ composite_type: str | None = None
composite_files: dict[str, Any] = {}
primary_file_name = "index"
# Allow user to change between this datatype and others. If left to None,
# datatype change is allowed if the datatype is not composite.
- allow_datatype_change: Optional[bool] = None
+ allow_datatype_change: bool | None = None
# A per datatype setting (inherited): max file size (in bytes) for setting optional metadata
_max_optional_metadata_filesize = None
# Display behavior when preview=True: "inline" (can be displayed in browser),
# "download" (always triggers download), or None (default behavior)
- display_behavior: Optional[Literal["inline", "download"]] = None
+ display_behavior: Literal["inline", "download"] | None = None
# Trackster track type.
- track_type: Optional[str] = None
+ track_type: str | None = None
# Data sources.
data_sources: dict[str, str] = {}
@@ -291,7 +289,7 @@ class Data(metaclass=DataMeta):
def groom_dataset_content(self, file_name: str) -> None:
"""This function is called on an output dataset file if dataset_content_needs_grooming returns True."""
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
# Metadata should be left mostly uninitialized. Dataset will
# handle returning default values when metadata is not set.
# copy_from allows metadata to be passed in that will be
@@ -304,7 +302,7 @@ class Data(metaclass=DataMeta):
def set_meta(self, dataset: DatasetProtocol, *, overwrite: bool = True, **kwd) -> None:
"""Unimplemented method, allows guessing of metadata from contents of file"""
- def missing_meta(self, dataset: HasMetadata, check: Optional[list] = None, skip: Optional[list] = None) -> bool:
+ def missing_meta(self, dataset: HasMetadata, check: list | None = None, skip: list | None = None) -> bool:
"""
Checks for empty metadata values.
Returns False if no non-optional metadata is missing and the missing metadata key otherwise.
@@ -399,7 +397,7 @@ class Data(metaclass=DataMeta):
def _archive_composite_dataset(
self, trans, data: DatasetHasHidProtocol, headers: Headers, do_action: str = "zip"
- ) -> tuple[Union[ZipstreamWrapper, str], Headers]:
+ ) -> tuple[ZipstreamWrapper | str, Headers]:
# save a composite object into a compressed archive for downloading
assert data.name
outfname = data.name[0:150]
@@ -445,7 +443,7 @@ class Data(metaclass=DataMeta):
yield fpath, rpath
def _serve_raw(
- self, dataset: DatasetHasHidProtocol, to_ext: Optional[str], headers: Headers, **kwd
+ self, dataset: DatasetHasHidProtocol, to_ext: str | None, headers: Headers, **kwd
) -> tuple[IO, Headers]:
headers["Content-Length"] = str(os.stat(dataset.get_file_name()).st_size)
headers["content-type"] = (
@@ -536,8 +534,8 @@ class Data(metaclass=DataMeta):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
**kwd,
):
"""
@@ -662,10 +660,10 @@ class Data(metaclass=DataMeta):
def _download_filename(
self,
dataset: DatasetHasHidProtocol,
- to_ext: Optional[str] = None,
- hdca: Optional[DatasetHasHidProtocol] = None,
- element_identifier: Optional[str] = None,
- filename_pattern: Optional[str] = None,
+ to_ext: str | None = None,
+ hdca: DatasetHasHidProtocol | None = None,
+ element_identifier: str | None = None,
+ filename_pattern: str | None = None,
) -> str:
if not to_ext or to_ext == "data":
# If a client requests to_ext with the extension 'data', they are
@@ -781,7 +779,7 @@ class Data(metaclass=DataMeta):
except Exception:
return UNKNOWN
- def as_display_type(self, dataset: DatasetProtocol, type: str, **kwd) -> Union[FileObjType, str]:
+ def as_display_type(self, dataset: DatasetProtocol, type: str, **kwd) -> FileObjType | str:
"""Returns modified file contents for a particular display type"""
try:
if type in self.get_display_types():
@@ -824,7 +822,7 @@ class Data(metaclass=DataMeta):
def find_conversion_destination(
self, dataset: DatasetProtocol, accepted_formats: list[str], datatypes_registry, **kwd
- ) -> tuple[bool, Optional[str], Any]:
+ ) -> tuple[bool, str | None, Any]:
"""Returns ( direct_match, converted_ext, existing converted dataset )"""
return datatypes_registry.find_conversion_destination_for_dataset_by_extensions(
dataset, accepted_formats, **kwd
@@ -837,8 +835,8 @@ class Data(metaclass=DataMeta):
target_type: str,
return_output: bool = False,
visible: bool = True,
- deps: Optional[dict] = None,
- target_context: Optional[dict] = None,
+ deps: dict | None = None,
+ target_context: dict | None = None,
history=None,
use_cached_job: bool = False,
):
@@ -898,9 +896,9 @@ class Data(metaclass=DataMeta):
self,
name: str,
optional: bool = False,
- mimetype: Optional[str] = None,
- description: Optional[str] = None,
- substitute_name_with_metadata: Optional[str] = None,
+ mimetype: str | None = None,
+ description: str | None = None,
+ substitute_name_with_metadata: str | None = None,
is_binary: bool = False,
to_posix_lines: bool = True,
space_to_tab: bool = False,
@@ -931,7 +929,7 @@ class Data(metaclass=DataMeta):
files[key] = value
return files
- def get_writable_files_for_dataset(self, dataset: Optional[HasMetadata]) -> dict:
+ def get_writable_files_for_dataset(self, dataset: HasMetadata | None) -> dict:
files = {}
if self.composite_type != "auto_primary_file":
files[self.primary_file_name] = self.__new_composite_file(self.primary_file_name)
@@ -939,7 +937,7 @@ class Data(metaclass=DataMeta):
files[key] = value
return files
- def get_composite_files(self, dataset: Optional[HasMetadata] = None):
+ def get_composite_files(self, dataset: HasMetadata | None = None):
def substitute_composite_key(key, composite_file):
if composite_file.substitute_name_with_metadata:
if dataset:
@@ -1064,7 +1062,7 @@ class Text(Data):
"""
dataset.metadata.data_lines = self.count_data_lines(dataset)
- def estimate_file_lines(self, dataset: DatasetProtocol) -> Optional[int]:
+ def estimate_file_lines(self, dataset: DatasetProtocol) -> int | None:
"""
Perform a rough estimate by extrapolating number of lines from a small read.
"""
@@ -1078,7 +1076,7 @@ class Text(Data):
log.warning(f"Unable to estimate lines in file {dataset.get_file_name()}, likely not a text file.")
return None
- def count_data_lines(self, dataset: HasFileName) -> Optional[int]:
+ def count_data_lines(self, dataset: HasFileName) -> int | None:
"""
Count the number of lines of data in dataset,
skipping all blank lines and comments.
@@ -1140,7 +1138,7 @@ class Text(Data):
dataset.blurb = "file purged from disk"
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""
Split the input files by line.
"""
@@ -1305,8 +1303,8 @@ class ZarrDirectory(Directory):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
**kwd,
):
if preview:
@@ -1319,7 +1317,7 @@ class ZarrDirectory(Directory):
return super().display_data(trans, dataset, preview, filename, to_ext, **kwd)
- def _find_store_root_folder_name(self, dataset: DatasetProtocol) -> Optional[str]:
+ def _find_store_root_folder_name(self, dataset: DatasetProtocol) -> str | None:
"""Returns the name of the root folder where the Zarr store is located.
The Zarr store can be directly in the extra files folder or in a subfolder.
@@ -1338,14 +1336,14 @@ class ZarrDirectory(Directory):
return sub_folder_name # The store is in a subfolder of the extra files folder
return None # The directory structure does not look like Zarr format
- def _load_zarr_metadata_file(self, store_root_path: str) -> Optional[dict[str, Any]]:
+ def _load_zarr_metadata_file(self, store_root_path: str) -> dict[str, Any] | None:
"""Returns the path to the metadata file in the Zarr store."""
if meta_file := self._find_zarr_metadata_file(store_root_path):
with open(meta_file) as f:
return json.load(f)
return None
- def _find_zarr_metadata_file(self, store_root_path: str) -> Optional[str]:
+ def _find_zarr_metadata_file(self, store_root_path: str) -> str | None:
"""Returns the path to the metadata file in the Zarr store."""
meta_file = None
files_in_store = os.listdir(store_root_path)
@@ -1363,7 +1361,7 @@ class ZarrDirectory(Directory):
return meta_file
return None
- def _get_format_version(self, store_root_path: str) -> Optional[str]:
+ def _get_format_version(self, store_root_path: str) -> str | None:
"""Returns the Zarr format version from the metadata file in the Zarr store."""
if metadata_file := self._load_zarr_metadata_file(store_root_path):
return metadata_file.get("zarr_format")
diff --git a/lib/galaxy/datatypes/display_applications/parameters.py b/lib/galaxy/datatypes/display_applications/parameters.py
index 2eb9423a2a7..e9117b74025 100644
--- a/lib/galaxy/datatypes/display_applications/parameters.py
+++ b/lib/galaxy/datatypes/display_applications/parameters.py
@@ -3,9 +3,7 @@ import mimetypes
from collections.abc import Callable
from dataclasses import dataclass
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
)
from urllib.parse import quote_plus
@@ -23,7 +21,7 @@ DEFAULT_DATASET_NAME = "dataset"
class DisplayApplicationParameter:
"""Abstract Class for Display Application Parameters"""
- type: Optional[str] = None
+ type: str | None = None
@classmethod
def from_elem(cls, elem, link):
@@ -72,7 +70,7 @@ class DatasetLikeObject:
state: DatasetState
extension: str
name: str
- dbkey: Optional[str]
+ dbkey: str | None
datatype: Data
@@ -116,7 +114,7 @@ class DisplayApplicationDataParameter(DisplayApplicationParameter):
)
return None
- def _get_dataset_like_object(self, other_values) -> Optional[Union[DatasetLikeObject, DatasetInstance]]:
+ def _get_dataset_like_object(self, other_values) -> DatasetLikeObject | DatasetInstance | None:
data = other_values.get(self.dataset, None)
assert data, "Base dataset could not be found in values provided to DisplayApplicationDataParameter"
if isinstance(data, DisplayDataValueWrapper):
diff --git a/lib/galaxy/datatypes/genetics.py b/lib/galaxy/datatypes/genetics.py
index e2539d2b41d..cedf39f1eef 100644
--- a/lib/galaxy/datatypes/genetics.py
+++ b/lib/galaxy/datatypes/genetics.py
@@ -18,8 +18,6 @@ import re
import sys
from typing import (
IO,
- Optional,
- Union,
)
from urllib.parse import quote_plus
@@ -84,7 +82,7 @@ class GenomeGraphs(Tabular):
t[0] = "string"
dataset.metadata.column_types = t
- def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> Union[FileObjType, str]:
+ def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> FileObjType | str:
"""
Returns file
"""
@@ -309,7 +307,7 @@ class Rgenetics(Html):
opt_text = " (optional)"
if composite_file.get("description"):
rval.append(
- f"{fn} ({composite_file.get('description')}) {opt_text} "
+ f'{fn} ({composite_file.get("description")}) {opt_text} '
)
else:
rval.append(f'{fn} {opt_text} ')
@@ -819,7 +817,7 @@ class RexpBase(Html):
f.write("\n".join(rval))
f.write("\n")
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
if copy_from:
dataset.metadata = copy_from.metadata
diff --git a/lib/galaxy/datatypes/gis.py b/lib/galaxy/datatypes/gis.py
index 8904bc8f581..53ffe29d9d8 100644
--- a/lib/galaxy/datatypes/gis.py
+++ b/lib/galaxy/datatypes/gis.py
@@ -75,7 +75,7 @@ class Shapefile(Binary):
opt_text = " (optional)"
if composite_file.get("description"):
rval.append(
- f"{fn} ({composite_file.get('description')}) {opt_text} "
+ f'{fn} ({composite_file.get("description")}) {opt_text} '
)
else:
rval.append(f'{fn} {opt_text} ')
diff --git a/lib/galaxy/datatypes/goldenpath.py b/lib/galaxy/datatypes/goldenpath.py
index 6b8c975c5b4..88ce28099c7 100644
--- a/lib/galaxy/datatypes/goldenpath.py
+++ b/lib/galaxy/datatypes/goldenpath.py
@@ -1,9 +1,6 @@
import abc
import logging
import os
-from typing import (
- Union,
-)
from galaxy.datatypes.protocols import DatasetProtocol
from galaxy.datatypes.sniff import (
@@ -176,7 +173,7 @@ class AGPFile:
if not all(fields):
raise AGPError(self.fname, line_number, "detected an empty field")
- agp_line: Union[AGPGapLine, AGPSeqLine]
+ agp_line: AGPGapLine | AGPSeqLine
# Instantiate all the AGPLine objects. These will do line-specific validations.
if fields[4] == "N" or fields[4] == "U":
agp_line = AGPGapLine(self.fname, line_number, *fields)
diff --git a/lib/galaxy/datatypes/hdf5.py b/lib/galaxy/datatypes/hdf5.py
index 3f40b2a496a..12080c70047 100644
--- a/lib/galaxy/datatypes/hdf5.py
+++ b/lib/galaxy/datatypes/hdf5.py
@@ -3,8 +3,6 @@
This datatype was created for use with the iSEE interactive tool.
"""
-from typing import Optional
-
from galaxy.datatypes.data import Data
from galaxy.datatypes.metadata import MetadataElement
from galaxy.datatypes.protocols import (
@@ -52,7 +50,7 @@ class HDF5SummarizedExperiment(Data):
description="Summarized experiment data array",
)
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
"""Override parent init metadata."""
Data.init_meta(self, dataset, copy_from=copy_from)
diff --git a/lib/galaxy/datatypes/images.py b/lib/galaxy/datatypes/images.py
index cb9567ea85f..40233bb400a 100644
--- a/lib/galaxy/datatypes/images.py
+++ b/lib/galaxy/datatypes/images.py
@@ -12,8 +12,6 @@ from collections.abc import Iterator
from typing import (
Any,
Literal,
- Optional,
- Union,
)
import mrcfile
@@ -156,7 +154,7 @@ class Image(data.Data):
return f""
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
"""
Try to populate the metadata of the image using a generic image loading library (Pillow), if available.
@@ -204,7 +202,7 @@ class Png(Image):
file_ext = "png"
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
"""
Try to populate the metadata of the image using PyPNG.
@@ -265,7 +263,7 @@ class Tiff(Image):
)
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
"""
Populate the metadata of the TIFF image using the tifffile library.
@@ -300,7 +298,6 @@ class Tiff(Image):
# TIFF files can contain multiple images, each represented by a series of pages
for series in tif.series:
-
# Determine the metadata values that should be generally available
metadata["axes"].append(series.axes.upper())
metadata["dtype"].append(str(series.dtype))
@@ -318,7 +315,6 @@ class Tiff(Image):
# Populate the metadata fields based on the values determined above
for key, values in metadata.items():
if len(values) > 0:
-
# Populate as plain value, if there is just one value, and as a list otherwise
if len(values) == 1:
setattr(dataset.metadata, key, values[0])
@@ -352,14 +348,13 @@ class Tiff(Image):
return shape[idx] if idx >= 0 else 0
@staticmethod
- def _get_num_unique_values(series: tifffile.TiffPageSeries) -> Optional[int]:
+ def _get_num_unique_values(series: tifffile.TiffPageSeries) -> int | None:
"""
Determines the number of unique values in a TIFF series of pages.
"""
unique_values: list[Any] = []
try:
for page in series.pages:
-
if page is None:
continue # No idea how this might occur, but mypy demands that we check it, just to be sure
@@ -372,19 +367,17 @@ class Tiff(Image):
@staticmethod
def _read_chunks(
- page: Union[tifffile.TiffPage, tifffile.TiffFrame], mmap_chunk_size: int = 2**14
+ page: tifffile.TiffPage | tifffile.TiffFrame, mmap_chunk_size: int = 2**14
) -> Iterator["np.typing.NDArray"]:
"""
Generator that reads all chunks of values from a TIFF page.
"""
if len(page.dataoffsets) > 1:
-
# There are multiple segments that can be processed consecutively
for segment in Tiff._read_segments(page):
yield segment.reshape(-1)
else:
-
# The page can be memory-mapped and processed chunk-wise
arr = page.asarray(out="memmap") # No considerable amounts of memory should be allocated here
arr_flat = arr.reshape(-1) # This should only produce a view without any new allocations
@@ -395,7 +388,7 @@ class Tiff(Image):
yield from np.array_split(arr_flat, chunks_count)
@staticmethod
- def _read_segments(page: Union[tifffile.TiffPage, tifffile.TiffFrame]) -> Iterator["np.typing.NDArray"]:
+ def _read_segments(page: tifffile.TiffPage | tifffile.TiffFrame) -> Iterator["np.typing.NDArray"]:
"""
Generator that reads all segments of a TIFF page.
"""
@@ -576,7 +569,7 @@ class Dicom(Image):
return "application/dicom"
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
"""
Populate the metadata of the DICOM file using the pydicom library.
@@ -635,17 +628,14 @@ class Dicom(Image):
# Try to infer `num_unique_values` from metadata
try:
if dcm.SOPClassUID == "1.2.840.10008.5.1.4.1.1.66.4": # https://www.dicomlibrary.com/dicom/sop
-
# The DICOM file contains segmentation, count +1 for the image background
dataset.metadata.num_unique_values = 1 + len(dcm.SegmentSequence)
else:
-
# Otherwise, `num_unique_values` is not available from metadata
dataset.metadata.num_unique_values = None
except AttributeError:
-
# Ignore errors if metadata cannot be read
dataset.metadata.num_unique_values = None
@@ -818,7 +808,7 @@ class Analyze75(Binary):
opt_text = " (optional)"
if composite_file.get("description"):
rval.append(
- f"{fn} ({composite_file.get('description')}) {opt_text} "
+ f'{fn} ({composite_file.get("description")}) {opt_text} '
)
else:
rval.append(f'{fn} {opt_text} ')
diff --git a/lib/galaxy/datatypes/interval.py b/lib/galaxy/datatypes/interval.py
index 9aef90ac6a6..ee7cb7850d8 100644
--- a/lib/galaxy/datatypes/interval.py
+++ b/lib/galaxy/datatypes/interval.py
@@ -5,10 +5,6 @@ Interval datatypes
import logging
import sys
import tempfile
-from typing import (
- Optional,
- Union,
-)
from urllib.parse import quote_plus
import pysam
@@ -123,7 +119,7 @@ class Interval(Tabular):
Tabular.__init__(self, **kwd)
self.add_display_app("ucsc", "display at UCSC", "as_ucsc_display_file", "ucsc_links")
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
Tabular.init_meta(self, dataset, copy_from=copy_from)
def set_meta(
@@ -202,10 +198,10 @@ class Interval(Tabular):
def get_estimated_display_viewport(
self,
dataset: DatasetProtocol,
- chrom_col: Optional[int] = None,
- start_col: Optional[int] = None,
- end_col: Optional[int] = None,
- ) -> tuple[Optional[str], Optional[str], Optional[str]]:
+ chrom_col: int | None = None,
+ start_col: int | None = None,
+ end_col: int | None = None,
+ ) -> tuple[str | None, str | None, str | None]:
"""Return a chrom, start, stop tuple for viewing a file."""
viewport_feature_count = 100 # viewport should check at least 100 features; excludes comment lines
max_line_count = max(viewport_feature_count, 500) # maximum number of lines to check; includes comment lines
@@ -263,7 +259,7 @@ class Interval(Tabular):
log.exception("Exception caught attempting to generate viewport for dataset '%d'", dataset.id)
return (None, None, None)
- def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> Union[FileObjType, str]:
+ def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> FileObjType | str:
"""Returns file contents with only the bed data"""
with tempfile.NamedTemporaryFile(delete=False, mode="w") as fh:
c, s, e, t, n = (
@@ -425,7 +421,7 @@ class BedGraph(Interval):
track_type = "LineTrack"
data_sources = {"data": "bigwig", "index": "bigwig"}
- def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> Union[FileObjType, str]:
+ def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> FileObjType | str:
"""
Returns file contents as is with no modifications.
TODO: this is a functional stub and will need to be enhanced moving forward to provide additional support for bedgraph.
@@ -435,10 +431,10 @@ class BedGraph(Interval):
def get_estimated_display_viewport(
self,
dataset: DatasetProtocol,
- chrom_col: Optional[int] = 0,
- start_col: Optional[int] = 1,
- end_col: Optional[int] = 2,
- ) -> tuple[Optional[str], Optional[str], Optional[str]]:
+ chrom_col: int | None = 0,
+ start_col: int | None = 1,
+ end_col: int | None = 2,
+ ) -> tuple[str | None, str | None, str | None]:
"""
Set viewport based on dataset's first 100 lines.
"""
@@ -514,7 +510,7 @@ class Bed(Interval):
break
Tabular.set_meta(self, dataset, overwrite=overwrite, skip=i)
- def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> Union[FileObjType, str]:
+ def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> FileObjType | str:
"""Returns file contents with only the bed data. If bed 6+, treat as interval."""
for line in open(dataset.get_file_name()):
line = line.strip()
@@ -875,9 +871,7 @@ class Gff(Tabular, _RemoteCallMixin):
"""Returns formated html of peek"""
return self.make_html_table(dataset, column_names=self.column_names)
- def get_estimated_display_viewport(
- self, dataset: DatasetProtocol
- ) -> tuple[Optional[str], Optional[str], Optional[str]]:
+ def get_estimated_display_viewport(self, dataset: DatasetProtocol) -> tuple[str | None, str | None, str | None]:
"""
Return a chrom, start, stop tuple for viewing a file. There are slight differences between gff 2 and gff 3
formats. This function should correctly handle both...
@@ -1287,9 +1281,7 @@ class Wiggle(Tabular, _RemoteCallMixin):
self.add_display_app("ucsc", "display at UCSC", "as_ucsc_display_file", "ucsc_links")
self.add_display_app("gbrowse", "display in Gbrowse", "as_gbrowse_display_file", "gbrowse_links")
- def get_estimated_display_viewport(
- self, dataset: DatasetProtocol
- ) -> tuple[Optional[str], Optional[str], Optional[str]]:
+ def get_estimated_display_viewport(self, dataset: DatasetProtocol) -> tuple[str | None, str | None, str | None]:
"""Return a chrom, start, stop tuple for viewing a file."""
viewport_feature_count = 100 # viewport should check at least 100 features; excludes comment lines
max_line_count = max(viewport_feature_count, 500) # maximum number of lines to check; includes comment lines
@@ -1475,10 +1467,10 @@ class CustomTrack(Tabular):
def get_estimated_display_viewport(
self,
dataset: DatasetProtocol,
- chrom_col: Optional[int] = None,
- start_col: Optional[int] = None,
- end_col: Optional[int] = None,
- ) -> tuple[Optional[str], Optional[str], Optional[str]]:
+ chrom_col: int | None = None,
+ start_col: int | None = None,
+ end_col: int | None = None,
+ ) -> tuple[str | None, str | None, str | None]:
"""Return a chrom, start, stop tuple for viewing a file."""
# FIXME: only BED and WIG custom tracks are currently supported
# As per previously existing behavior, viewport will only be over the first intervals
@@ -1781,7 +1773,7 @@ class IntervalTabix(Interval):
dataset: DatasetProtocol,
overwrite: bool = True,
first_line_is_header: bool = False,
- metadata_tmp_files_dir: Optional[str] = None,
+ metadata_tmp_files_dir: str | None = None,
**kwd,
) -> None:
# We don't use the method Interval.set_meta as we don't want to guess the columns for chr start end
diff --git a/lib/galaxy/datatypes/isa.py b/lib/galaxy/datatypes/isa.py
index 4c12aa86fc2..7117967e453 100644
--- a/lib/galaxy/datatypes/isa.py
+++ b/lib/galaxy/datatypes/isa.py
@@ -12,7 +12,6 @@ import re
import shutil
import tempfile
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -204,10 +203,10 @@ class _Isa(Data):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
- offset: Optional[int] = None,
- ck_size: Optional[int] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
+ offset: int | None = None,
+ ck_size: int | None = None,
**kwd,
):
"""Downloads the ISA dataset if `preview` is `False`;
diff --git a/lib/galaxy/datatypes/molecules.py b/lib/galaxy/datatypes/molecules.py
index d0246294d69..b6100795bce 100644
--- a/lib/galaxy/datatypes/molecules.py
+++ b/lib/galaxy/datatypes/molecules.py
@@ -2,9 +2,6 @@ import logging
import os
import re
from collections.abc import Callable
-from typing import (
- Optional,
-)
from galaxy.datatypes import metadata
from galaxy.datatypes.binary import Binary
@@ -387,7 +384,7 @@ class SDF(GenericMolFile):
dataset.metadata.number_of_molecules = count_special_lines(r"^\$\$\$\$$", dataset.get_file_name())
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""
Split the input files by molecule records.
"""
@@ -400,7 +397,7 @@ class SDF(GenericMolFile):
chunk_size = None
if split_params["split_mode"] == "number_of_parts":
- raise Exception(f"Split mode \"{split_params['split_mode']}\" is currently not implemented for SD-files.")
+ raise Exception(f'Split mode "{split_params["split_mode"]}" is currently not implemented for SD-files.')
elif split_params["split_mode"] == "to_size":
chunk_size = int(split_params["split_size"])
else:
@@ -470,7 +467,7 @@ class MOL2(GenericMolFile):
dataset.metadata.number_of_molecules = count_special_lines("@MOLECULE", dataset.get_file_name())
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""
Split the input files by molecule records.
"""
@@ -483,7 +480,7 @@ class MOL2(GenericMolFile):
chunk_size = None
if split_params["split_mode"] == "number_of_parts":
- raise Exception(f"Split mode \"{split_params['split_mode']}\" is currently not implemented for MOL2-files.")
+ raise Exception(f'Split mode "{split_params["split_mode"]}" is currently not implemented for MOL2-files.')
elif split_params["split_mode"] == "to_size":
chunk_size = int(split_params["split_size"])
else:
@@ -556,7 +553,7 @@ class FPS(GenericMolFile):
dataset.metadata.number_of_molecules = count_special_lines("^#", dataset.get_file_name(), invert=True)
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""
Split the input files by fingerprint records.
"""
@@ -569,7 +566,7 @@ class FPS(GenericMolFile):
chunk_size = None
if split_params["split_mode"] == "number_of_parts":
- raise Exception(f"Split mode \"{split_params['split_mode']}\" is currently not implemented for MOL2-files.")
+ raise Exception(f'Split mode "{split_params["split_mode"]}" is currently not implemented for MOL2-files.')
elif split_params["split_mode"] == "to_size":
chunk_size = int(split_params["split_size"])
else:
@@ -680,7 +677,7 @@ class OBFS(Binary):
raise NotImplementedError("Merging Fastsearch indices is not supported.")
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""Splitting Fastsearch indices is not supported."""
if split_params is None:
return None
@@ -1410,7 +1407,7 @@ class CML(GenericXml):
return True
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""
Split the input files by molecule records.
"""
@@ -1423,7 +1420,7 @@ class CML(GenericXml):
chunk_size = None
if split_params["split_mode"] == "number_of_parts":
- raise Exception(f"Split mode \"{split_params['split_mode']}\" is currently not implemented for CML-files.")
+ raise Exception(f'Split mode "{split_params["split_mode"]}" is currently not implemented for CML-files.')
elif split_params["split_mode"] == "to_size":
chunk_size = int(split_params["split_size"])
else:
diff --git a/lib/galaxy/datatypes/mothur.py b/lib/galaxy/datatypes/mothur.py
index a183199822a..d5d20b4c780 100644
--- a/lib/galaxy/datatypes/mothur.py
+++ b/lib/galaxy/datatypes/mothur.py
@@ -4,9 +4,6 @@ Mothur Metagenomics Datatypes
import logging
import re
-from typing import (
- Optional,
-)
from galaxy.datatypes.data import Text
from galaxy.datatypes.metadata import MetadataElement
@@ -126,7 +123,7 @@ class Sabund(Otu):
"""
super().__init__(**kwd)
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
super().init_meta(dataset, copy_from=copy_from)
def sniff_prefix(self, file_prefix: FilePrefix) -> bool:
@@ -170,10 +167,10 @@ class GroupAbund(Otu):
def __init__(self, **kwd):
super().__init__(**kwd)
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
super().init_meta(dataset, copy_from=copy_from)
- def set_meta(self, dataset: DatasetProtocol, overwrite: bool = True, skip: Optional[int] = 1, **kwd) -> None:
+ def set_meta(self, dataset: DatasetProtocol, overwrite: bool = True, skip: int | None = 1, **kwd) -> None:
super().set_meta(dataset, overwrite=overwrite, **kwd)
# See if file starts with header line
@@ -351,10 +348,10 @@ class DistanceMatrix(Text):
no_value="?",
)
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
super().init_meta(dataset, copy_from=copy_from)
- def set_meta(self, dataset: DatasetProtocol, overwrite: bool = True, skip: Optional[int] = 0, **kwd) -> None:
+ def set_meta(self, dataset: DatasetProtocol, overwrite: bool = True, skip: int | None = 0, **kwd) -> None:
super().set_meta(dataset, overwrite=overwrite, skip=skip, **kwd)
headers = iter_headers(dataset.get_file_name(), sep="\t")
@@ -376,7 +373,7 @@ class LowerTriangleDistanceMatrix(DistanceMatrix):
"""Initialize secondary structure map datatype"""
super().__init__(**kwd)
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
super().init_meta(dataset, copy_from=copy_from)
def sniff_prefix(self, file_prefix: FilePrefix) -> bool:
@@ -441,7 +438,7 @@ class SquareDistanceMatrix(DistanceMatrix):
def __init__(self, **kwd):
super().__init__(**kwd)
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
super().init_meta(dataset, copy_from=copy_from)
def sniff_prefix(self, file_prefix: FilePrefix) -> bool:
@@ -507,7 +504,7 @@ class PairwiseDistanceMatrix(DistanceMatrix, Tabular):
self.column_names = ["Sequence", "Sequence", "Distance"]
self.column_types = ["str", "str", "float"]
- def set_meta(self, dataset: DatasetProtocol, overwrite: bool = True, skip: Optional[int] = None, **kwd) -> None:
+ def set_meta(self, dataset: DatasetProtocol, overwrite: bool = True, skip: int | None = None, **kwd) -> None:
super().set_meta(dataset, overwrite=overwrite, skip=skip, **kwd)
def sniff_prefix(self, file_prefix: FilePrefix) -> bool:
@@ -599,8 +596,8 @@ class Group(Tabular):
self,
dataset: DatasetProtocol,
overwrite: bool = True,
- skip: Optional[int] = None,
- max_data_lines: Optional[int] = None,
+ skip: int | None = None,
+ max_data_lines: int | None = None,
**kwd,
) -> None:
super().set_meta(dataset, overwrite=overwrite, skip=skip, max_data_lines=max_data_lines, **kwd)
@@ -847,8 +844,8 @@ class CountTable(Tabular):
self,
dataset: DatasetProtocol,
overwrite: bool = True,
- skip: Optional[int] = 1,
- max_data_lines: Optional[int] = None,
+ skip: int | None = 1,
+ max_data_lines: int | None = None,
**kwd,
) -> None:
super().set_meta(dataset, overwrite=overwrite, **kwd)
@@ -1059,8 +1056,8 @@ class SffFlow(Tabular):
self,
dataset: DatasetProtocol,
overwrite: bool = True,
- skip: Optional[int] = 1,
- max_data_lines: Optional[int] = None,
+ skip: int | None = 1,
+ max_data_lines: int | None = None,
**kwd,
) -> None:
super().set_meta(dataset, overwrite=overwrite, skip=1, max_data_lines=max_data_lines, **kwd)
@@ -1072,7 +1069,7 @@ class SffFlow(Tabular):
except Exception as e:
log.warning(f"SffFlow set_meta {e}")
- def make_html_table(self, dataset: DatasetProtocol, skipchars: Optional[list] = None, **kwargs) -> str:
+ def make_html_table(self, dataset: DatasetProtocol, skipchars: list | None = None, **kwargs) -> str:
"""Create HTML table, used for displaying peek"""
skipchars = skipchars or []
try:
diff --git a/lib/galaxy/datatypes/msa.py b/lib/galaxy/datatypes/msa.py
index 43d09e47c4f..6ddd8b54d6d 100644
--- a/lib/galaxy/datatypes/msa.py
+++ b/lib/galaxy/datatypes/msa.py
@@ -3,9 +3,6 @@ import logging
import os
import re
from collections.abc import Callable
-from typing import (
- Optional,
-)
from galaxy.datatypes.binary import Binary
from galaxy.datatypes.data import (
@@ -204,7 +201,7 @@ class Stockholm_1_0(Text):
)
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""
Split the input files by model records.
@@ -219,7 +216,7 @@ class Stockholm_1_0(Text):
chunk_size = None
if split_params["split_mode"] == "number_of_parts":
raise Exception(
- f"Split mode \"{split_params['split_mode']}\" is currently not implemented for STOCKHOLM-files."
+ f'Split mode "{split_params["split_mode"]}" is currently not implemented for STOCKHOLM-files.'
)
elif split_params["split_mode"] == "to_size":
chunk_size = int(split_params["split_size"])
diff --git a/lib/galaxy/datatypes/proteomics.py b/lib/galaxy/datatypes/proteomics.py
index 0444efa2ac8..7113790f62f 100644
--- a/lib/galaxy/datatypes/proteomics.py
+++ b/lib/galaxy/datatypes/proteomics.py
@@ -6,7 +6,6 @@ import logging
import re
from typing import (
IO,
- Optional,
)
from galaxy.datatypes import data
@@ -66,7 +65,7 @@ class Wiff(Binary):
opt_text = " (optional)"
if composite_file.get("description"):
rval.append(
- f"{fn} ({composite_file.get('description')}) {opt_text} "
+ f'{fn} ({composite_file.get("description")}) {opt_text} '
)
else:
rval.append(f'{fn} {opt_text} ')
@@ -108,7 +107,7 @@ class Wiff2(Binary):
opt_text = " (optional)"
if composite_file.get("description"):
rval.append(
- f"{fn} ({composite_file.get('description')}) {opt_text} "
+ f'{fn} ({composite_file.get("description")}) {opt_text} '
)
else:
rval.append(f'{fn} {opt_text} ')
@@ -207,8 +206,8 @@ class MzTab2(MzTab):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
**kwd,
):
if to_ext == self.file_ext:
@@ -500,7 +499,7 @@ class Dta2d(TabularData):
file_ext = "dta2d"
comment_lines = 0
- def _parse_header(self, line: list) -> Optional[list]:
+ def _parse_header(self, line: list) -> list | None:
if len(line) != 3 or len(line[0]) < 3 or not line[0].startswith("#"):
return None
line[0] = line[0].lstrip("#")
@@ -509,7 +508,7 @@ class Dta2d(TabularData):
return None
return line
- def _parse_delimiter(self, line: str) -> Optional[str]:
+ def _parse_delimiter(self, line: str) -> str | None:
if len(line.split(" ")) == 3:
return " "
elif len(line.split("\t")) == 3:
@@ -602,7 +601,7 @@ class Edta(TabularData):
file_ext = "edta"
comment_lines = 0
- def _parse_delimiter(self, line: str) -> Optional[str]:
+ def _parse_delimiter(self, line: str) -> str | None:
if len(line.split(" ")) >= 3:
return " "
elif len(line.split("\t")) >= 3:
@@ -611,7 +610,7 @@ class Edta(TabularData):
return "\t"
return None
- def _parse_type(self, line: list) -> Optional[int]:
+ def _parse_type(self, line: list) -> int | None:
"""
parse the type from the header line
types 1-3 as in the class docs, 0: type 1 wo/wrong header
@@ -631,7 +630,7 @@ class Edta(TabularData):
else:
return 3
- def _parse_dataline(self, line: list, tpe: Optional[int]) -> bool:
+ def _parse_dataline(self, line: list, tpe: int | None) -> bool:
if tpe == 2 or tpe == 3:
idx = 4
else:
@@ -1055,7 +1054,7 @@ class SPLib(Msp):
opt_text = " (optional)"
if composite_file.get("description"):
rval.append(
- f"{fn} ({composite_file.get('description')}) {opt_text} "
+ f'{fn} ({composite_file.get("description")}) {opt_text} '
)
else:
rval.append(f'{fn} {opt_text} ')
@@ -1142,7 +1141,7 @@ class ImzML(Binary):
opt_text = ""
if composite_file.get("description"):
rval.append(
- f"{fn} ({composite_file.get('description')}) {opt_text} "
+ f'{fn} ({composite_file.get("description")}) {opt_text} '
)
else:
rval.append(f'{fn} {opt_text} ')
diff --git a/lib/galaxy/datatypes/qiime2.py b/lib/galaxy/datatypes/qiime2.py
index ed1281eace5..af2cfbb3203 100644
--- a/lib/galaxy/datatypes/qiime2.py
+++ b/lib/galaxy/datatypes/qiime2.py
@@ -3,9 +3,6 @@ import html
import io
import uuid as _uuid
import zipfile
-from typing import (
- Optional,
-)
import yaml
@@ -69,7 +66,7 @@ class _QIIME2ResultBase(CompressedZipArchive):
peek.append(("Version", dataset.metadata.version))
return peek
- def _sniff(self, filename: str) -> Optional[dict]:
+ def _sniff(self, filename: str) -> dict | None:
"""Helper method for use in inherited datatypes"""
try:
if not zipfile.is_zipfile(filename):
@@ -114,7 +111,7 @@ class QIIME2Metadata(Tabular):
_TYPES_DIRECTIVE = "#q2:types"
_search_lines = 2
- def get_column_names(self, first_line: str) -> Optional[list[str]]:
+ def get_column_names(self, first_line: str) -> list[str] | None:
return first_line.strip().split("\t")
def set_meta(self, dataset: DatasetProtocol, overwrite: bool = True, **kwd) -> None:
diff --git a/lib/galaxy/datatypes/registry.py b/lib/galaxy/datatypes/registry.py
index 8604531ec0a..f9b9b4dfbfa 100644
--- a/lib/galaxy/datatypes/registry.py
+++ b/lib/galaxy/datatypes/registry.py
@@ -123,8 +123,8 @@ class Registry:
def load_datatypes(
self,
- root_dir: Optional[StrPath] = None,
- config: Optional[Union[Element, StrPath]] = None,
+ root_dir: StrPath | None = None,
+ config: Element | StrPath | None = None,
override: bool = True,
use_converters: bool = True,
use_display_applications: bool = True,
@@ -218,7 +218,7 @@ class Registry:
if override or extension not in self.datatypes_by_extension:
can_process_datatype = True
if can_process_datatype:
- datatype_class: Optional[type[Data]] = None
+ datatype_class: type[Data] | None = None
if dtype is not None:
ok = True
try:
@@ -541,7 +541,7 @@ class Registry:
self,
root: Element,
override: bool = False,
- compressed_sniffers: Optional[dict[type["Data"], list["Data"]]] = None,
+ compressed_sniffers: dict[type["Data"], list["Data"]] | None = None,
) -> None:
"""
Process the sniffers element from a parsed a datatypes XML file located at root_dir/config (if processing the Galaxy
@@ -934,10 +934,10 @@ class Registry:
def find_conversion_destination_for_dataset_by_extensions(
self,
- dataset_or_ext: Union[str, DatasetProtocol],
+ dataset_or_ext: str | DatasetProtocol,
accepted_formats: Iterable[Union[str, "Data"]],
converter_safe: bool = True,
- ) -> tuple[bool, Optional[str], Optional[DatasetProtocol]]:
+ ) -> tuple[bool, str | None, DatasetProtocol | None]:
"""
returns (direct_match, converted_ext, converted_dataset)
- direct match is True iff no the data set already has an accepted format
@@ -1088,7 +1088,7 @@ class Registry:
return state
-def upload_warning(template: Optional[Template], auto_compressed_type: Optional[str] = None) -> Optional[str]:
+def upload_warning(template: Template | None, auto_compressed_type: str | None = None) -> str | None:
if template is None:
return None
template_args = {"auto_compressed_type": "" if auto_compressed_type is None else f".{auto_compressed_type}"}
diff --git a/lib/galaxy/datatypes/sequence.py b/lib/galaxy/datatypes/sequence.py
index fed04fa3d0f..ee9fe489ae1 100644
--- a/lib/galaxy/datatypes/sequence.py
+++ b/lib/galaxy/datatypes/sequence.py
@@ -16,7 +16,6 @@ from collections.abc import (
from itertools import islice
from typing import (
Any,
- Optional,
)
import bx.align.maf
@@ -219,7 +218,7 @@ class Sequence(data.Text):
return directories
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""Split a generic sequence file (not sensible or possible, see subclasses)."""
if split_params is None:
return None
@@ -324,8 +323,8 @@ class Sequence(data.Text):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
**kwd,
):
headers = kwd.get("headers", {})
@@ -356,7 +355,7 @@ class Alignment(data.Text):
)
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""Split a generic alignment file (not sensible or possible, see subclasses)."""
if split_params is None:
return None
@@ -444,7 +443,7 @@ class Fasta(Sequence):
return False
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""Split a FASTA file sequence by sequence.
Note that even if split_mode="number_of_parts", the actual number of
@@ -792,7 +791,7 @@ class BaseFastq(Sequence):
return self.check_first_block(file_prefix)
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""
FASTQ files are split on cluster boundaries, in increments of 4 lines
"""
@@ -1008,11 +1007,11 @@ class Maf(Alignment):
optional=True,
)
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
Alignment.init_meta(self, dataset, copy_from=copy_from)
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
"""
Parses and sets species, chromosomes, index from MAF file.
@@ -1064,7 +1063,7 @@ class Maf(Alignment):
"""Returns formated html of peek"""
return self.make_html_table(dataset)
- def make_html_table(self, dataset: DatasetProtocol, skipchars: Optional[list] = None) -> str:
+ def make_html_table(self, dataset: DatasetProtocol, skipchars: list | None = None) -> str:
"""Create HTML table, used for displaying peek"""
skipchars = skipchars or []
try:
diff --git a/lib/galaxy/datatypes/sniff.py b/lib/galaxy/datatypes/sniff.py
index 0b1b4cb5d23..0745b20a723 100644
--- a/lib/galaxy/datatypes/sniff.py
+++ b/lib/galaxy/datatypes/sniff.py
@@ -20,7 +20,6 @@ from functools import partial
from typing import (
IO,
NamedTuple,
- Optional,
TYPE_CHECKING,
Union,
)
@@ -97,22 +96,22 @@ def handle_composite_file(datatype, src_path, extra_files, name, is_binary, tmp_
class ConvertResult(NamedTuple):
line_count: int
- converted_path: Optional[str]
+ converted_path: str | None
converted_newlines: bool
converted_regex: bool
class ConvertFunction(Protocol):
def __call__(
- self, fname: str, in_place: bool = True, tmp_dir: Optional[str] = None, tmp_prefix: Optional[str] = "gxupload"
+ self, fname: str, in_place: bool = True, tmp_dir: str | None = None, tmp_prefix: str | None = "gxupload"
) -> ConvertResult: ...
def convert_newlines(
fname: str,
in_place: bool = True,
- tmp_dir: Optional[str] = None,
- tmp_prefix: Optional[str] = "gxupload",
+ tmp_dir: str | None = None,
+ tmp_prefix: str | None = "gxupload",
block_size: int = 128 * 1024,
regexp=None,
) -> ConvertResult:
@@ -166,8 +165,8 @@ def convert_newlines(
def convert_sep2tabs(
fname: str,
in_place: bool = True,
- tmp_dir: Optional[str] = None,
- tmp_prefix: Optional[str] = "gxupload",
+ tmp_dir: str | None = None,
+ tmp_prefix: str | None = "gxupload",
block_size: int = 128 * 1024,
):
"""
@@ -201,7 +200,7 @@ def convert_sep2tabs(
def convert_newlines_sep2tabs(
- fname: str, in_place: bool = True, tmp_dir: Optional[str] = None, tmp_prefix: Optional[str] = "gxupload"
+ fname: str, in_place: bool = True, tmp_dir: str | None = None, tmp_prefix: str | None = "gxupload"
) -> ConvertResult:
"""
Converts newlines in a file to posix newlines and replaces spaces with tabs.
@@ -695,7 +694,7 @@ class FilePrefix:
return self.contents_header_bytes.startswith(test_bytes)
-def _get_file_prefix(filename_or_file_prefix: Union[str, FilePrefix], auto_decompress: bool = True) -> FilePrefix:
+def _get_file_prefix(filename_or_file_prefix: str | FilePrefix, auto_decompress: bool = True) -> FilePrefix:
if not isinstance(filename_or_file_prefix, FilePrefix):
return FilePrefix(filename_or_file_prefix, auto_decompress=auto_decompress)
return filename_or_file_prefix
@@ -789,16 +788,16 @@ class HandleCompressedFileResponse(NamedTuple):
is_valid: bool
ext: str
uncompressed_path: str
- compressed_type: Optional[str]
- is_compressed: Optional[bool]
+ compressed_type: str | None
+ is_compressed: bool | None
def handle_compressed_file(
file_prefix: FilePrefix,
datatypes_registry,
ext: str = "auto",
- tmp_prefix: Optional[str] = "sniff_uncompress_",
- tmp_dir: Optional[str] = None,
+ tmp_prefix: str | None = "sniff_uncompress_",
+ tmp_dir: str | None = None,
in_place: bool = False,
check_content: bool = True,
) -> HandleCompressedFileResponse:
@@ -877,7 +876,7 @@ def handle_uploaded_dataset_file(filename, *args, **kwds) -> str:
class HandleUploadedDatasetFileInternalResponse(NamedTuple):
ext: str
converted_path: str
- compressed_type: Optional[str]
+ compressed_type: str | None
converted_newlines: bool
converted_spaces: bool
@@ -897,14 +896,14 @@ def handle_uploaded_dataset_file_internal(
file_prefix: FilePrefix,
datatypes_registry,
ext: str = "auto",
- tmp_prefix: Optional[str] = "sniff_upload_",
- tmp_dir: Optional[str] = None,
+ tmp_prefix: str | None = "sniff_upload_",
+ tmp_dir: str | None = None,
in_place: bool = False,
check_content: bool = True,
- is_binary: Optional[bool] = None,
- uploaded_file_ext: Optional[str] = None,
- convert_to_posix_lines: Optional[bool] = None,
- convert_spaces_to_tabs: Optional[bool] = None,
+ is_binary: bool | None = None,
+ uploaded_file_ext: str | None = None,
+ convert_to_posix_lines: bool | None = None,
+ convert_spaces_to_tabs: bool | None = None,
) -> HandleUploadedDatasetFileInternalResponse:
is_valid, ext, converted_path, compressed_type, is_compressed = handle_compressed_file(
file_prefix,
diff --git a/lib/galaxy/datatypes/spaln.py b/lib/galaxy/datatypes/spaln.py
index a2c477048b1..74a856086c1 100644
--- a/lib/galaxy/datatypes/spaln.py
+++ b/lib/galaxy/datatypes/spaln.py
@@ -5,9 +5,6 @@ spaln Composite Dataset
import logging
import os.path
from collections.abc import Callable
-from typing import (
- Optional,
-)
from galaxy.datatypes.data import Data
from galaxy.datatypes.metadata import MetadataElement
@@ -116,10 +113,10 @@ class _SpalnDb(Data):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
- offset: Optional[int] = None,
- ck_size: Optional[int] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
+ offset: int | None = None,
+ ck_size: int | None = None,
**kwd,
):
"""
@@ -169,7 +166,7 @@ class _SpalnDb(Data):
raise NotImplementedError("Merging spaln databases is not possible")
@classmethod
- def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: Optional[dict]) -> None:
+ def split(cls, input_datasets: list, subdir_generator_function: Callable, split_params: dict | None) -> None:
"""Split a spaln database (not implemented)."""
if split_params is None:
return None
diff --git a/lib/galaxy/datatypes/tabular.py b/lib/galaxy/datatypes/tabular.py
index 1e4f0e0cec0..fb4a51a8773 100644
--- a/lib/galaxy/datatypes/tabular.py
+++ b/lib/galaxy/datatypes/tabular.py
@@ -14,8 +14,6 @@ import tempfile
from json import dumps
from typing import (
cast,
- Optional,
- Union,
)
import pysam
@@ -143,7 +141,7 @@ class TabularData(Text):
except Exception:
return False
- def get_chunk(self, trans, dataset: HasFileName, offset: int = 0, ck_size: Optional[int] = None) -> str:
+ def get_chunk(self, trans, dataset: HasFileName, offset: int = 0, ck_size: int | None = None) -> str:
ck_data, last_read = self._read_chunk(trans, dataset, offset, ck_size)
return dumps(
{
@@ -153,7 +151,7 @@ class TabularData(Text):
}
)
- def _read_chunk(self, trans, dataset: HasFileName, offset: int, ck_size: Optional[int] = None):
+ def _read_chunk(self, trans, dataset: HasFileName, offset: int, ck_size: int | None = None):
with compression_utils.get_fileobj(dataset.get_file_name()) as f:
f.seek(offset)
try:
@@ -177,10 +175,10 @@ class TabularData(Text):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
- offset: Optional[int] = None,
- ck_size: Optional[int] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
+ offset: int | None = None,
+ ck_size: int | None = None,
**kwd,
):
headers = kwd.pop("headers", {})
@@ -229,10 +227,10 @@ class TabularData(Text):
def make_html_peek_header(
self,
dataset: DatasetProtocol,
- skipchars: Optional[list] = None,
- column_names: Optional[list] = None,
+ skipchars: list | None = None,
+ column_names: list | None = None,
column_number_format: str = "%s",
- column_parameter_alias: Optional[dict] = None,
+ column_parameter_alias: dict | None = None,
**kwargs,
) -> str:
if skipchars is None:
@@ -282,7 +280,7 @@ class TabularData(Text):
raise Exception(f"Can't create peek header: {util.unicodify(exc)}")
return "".join(out)
- def make_html_peek_rows(self, dataset: DatasetProtocol, skipchars: Optional[list] = None, **kwargs) -> str:
+ def make_html_peek_rows(self, dataset: DatasetProtocol, skipchars: list | None = None, **kwargs) -> str:
if skipchars is None:
skipchars = []
out = []
@@ -387,7 +385,7 @@ class Tabular(TabularData):
file_ext = "tabular"
- def get_column_names(self, first_line: str) -> Optional[list[str]]:
+ def get_column_names(self, first_line: str) -> list[str] | None:
return None
def set_meta(
@@ -395,9 +393,9 @@ class Tabular(TabularData):
dataset: DatasetProtocol,
*,
overwrite: bool = True,
- skip: Optional[int] = None,
- max_data_lines: Optional[int] = MAX_DATA_LINES,
- max_guess_type_data_lines: Optional[int] = None,
+ skip: int | None = None,
+ max_data_lines: int | None = MAX_DATA_LINES,
+ max_guess_type_data_lines: int | None = None,
**kwd,
) -> None:
"""
@@ -561,10 +559,10 @@ class Tabular(TabularData):
if column_names is not None:
dataset.metadata.column_names = column_names
- def as_gbrowse_display_file(self, dataset: HasFileName, **kwd) -> Union[FileObjType, str]:
+ def as_gbrowse_display_file(self, dataset: HasFileName, **kwd) -> FileObjType | str:
return open(dataset.get_file_name(), "rb")
- def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> Union[FileObjType, str]:
+ def as_ucsc_display_file(self, dataset: DatasetProtocol, **kwd) -> FileObjType | str:
return open(dataset.get_file_name(), "rb")
@@ -578,7 +576,7 @@ class SraManifest(Tabular):
super().set_meta(dataset, overwrite=overwrite, **kwd)
dataset.metadata.comment_lines = 1
- def get_column_names(self, first_line: str) -> Optional[list[str]]:
+ def get_column_names(self, first_line: str) -> list[str] | None:
return first_line.strip().split("\t")
@@ -766,8 +764,8 @@ class Sam(Tabular, _BamOrSam):
self,
dataset: DatasetProtocol,
overwrite: bool = True,
- skip: Optional[int] = None,
- max_data_lines: Optional[int] = 5,
+ skip: int | None = None,
+ max_data_lines: int | None = 5,
**kwd,
) -> None:
"""
@@ -919,7 +917,7 @@ class Pileup(Tabular):
MetadataElement(name="endCol", default=2, desc="End column", param=metadata.ColumnParameter)
MetadataElement(name="baseCol", default=3, desc="Reference base column", param=metadata.ColumnParameter)
- def init_meta(self, dataset: HasMetadata, copy_from: Optional[HasMetadata] = None) -> None:
+ def init_meta(self, dataset: HasMetadata, copy_from: HasMetadata | None = None) -> None:
super().init_meta(dataset, copy_from=copy_from)
def display_peek(self, dataset: DatasetProtocol) -> str:
@@ -1017,7 +1015,7 @@ class BaseVcf(Tabular):
name="sample_names", default=[], desc="Sample names", readonly=True, visible=False, optional=True, no_value=[]
)
- def _sniff(self, fname_or_file_prefix: Union[str, FilePrefix]) -> bool:
+ def _sniff(self, fname_or_file_prefix: str | FilePrefix) -> bool:
# Because this sniffer is run on compressed files that might be BGZF (due to the VcfGz subclass), we should
# handle unicode decode errors. This should ultimately be done in get_headers(), but guess_ext() currently
# relies on get_headers() raising this exception.
@@ -1109,7 +1107,7 @@ class VcfGz(BaseVcf, binary.Binary):
return binascii.hexlify(last28) == b"1f8b08040000000000ff0600424302001b0003000000000000000000"
def set_meta(
- self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: Optional[str] = None, **kwd
+ self, dataset: DatasetProtocol, overwrite: bool = True, metadata_tmp_files_dir: str | None = None, **kwd
) -> None:
super().set_meta(dataset, overwrite=overwrite, **kwd)
# Creates the index for the VCF file.
@@ -1213,7 +1211,7 @@ class Eland(Tabular):
]
def make_html_table(
- self, dataset: DatasetProtocol, skipchars: Optional[list] = None, peek: Optional[list] = None, **kwargs
+ self, dataset: DatasetProtocol, skipchars: list | None = None, peek: list | None = None, **kwargs
) -> str:
"""Create HTML table, used for displaying peek"""
skipchars = skipchars or []
@@ -1276,8 +1274,8 @@ class Eland(Tabular):
self,
dataset: DatasetProtocol,
overwrite: bool = True,
- skip: Optional[int] = None,
- max_data_lines: Optional[int] = 5,
+ skip: int | None = None,
+ max_data_lines: int | None = 5,
**kwd,
) -> None:
if dataset.has_data():
@@ -1625,7 +1623,7 @@ class ConnectivityTable(Tabular):
i += 1
return False
- def get_chunk(self, trans, dataset: HasFileName, offset: int = 0, ck_size: Optional[int] = None) -> str:
+ def get_chunk(self, trans, dataset: HasFileName, offset: int = 0, ck_size: int | None = None) -> str:
ck_data, last_read = self._read_chunk(trans, dataset, offset, ck_size)
try:
# The ConnectivityTable format has several derivatives of which one is delimited by (multiple) spaces.
@@ -1695,8 +1693,8 @@ class MatrixMarket(TabularData):
self,
dataset: DatasetProtocol,
overwrite: bool = True,
- skip: Optional[int] = None,
- max_data_lines: Optional[int] = 5,
+ skip: int | None = None,
+ max_data_lines: int | None = 5,
**kwd,
) -> None:
if dataset.has_data():
@@ -1823,8 +1821,8 @@ class CMAP(TabularData):
self,
dataset: DatasetProtocol,
overwrite: bool = True,
- skip: Optional[int] = None,
- max_data_lines: Optional[int] = 7,
+ skip: int | None = None,
+ max_data_lines: int | None = 7,
**kwd,
) -> None:
if dataset.has_data():
diff --git a/lib/galaxy/datatypes/text.py b/lib/galaxy/datatypes/text.py
index 84798642c00..781d87dda2e 100644
--- a/lib/galaxy/datatypes/text.py
+++ b/lib/galaxy/datatypes/text.py
@@ -10,7 +10,6 @@ import subprocess
import tempfile
from typing import (
IO,
- Optional,
)
import ijson
@@ -210,8 +209,8 @@ class Ipynb(Json):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
**kwd,
):
config = trans.app.config
@@ -226,8 +225,8 @@ class Ipynb(Json):
trans,
dataset: DatasetHasHidProtocol,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
**kwd,
) -> tuple[IO, Headers]:
headers = kwd.pop("headers", {})
@@ -950,7 +949,7 @@ class SnpEffDb(Text):
super().__init__(**kwd)
# The SnpEff version line was added in SnpEff version 4.1
- def getSnpeffVersionFromFile(self, path: str) -> Optional[str]:
+ def getSnpeffVersionFromFile(self, path: str) -> str | None:
snpeff_version = None
try:
with gzip.open(path, "rt") as fh:
diff --git a/lib/galaxy/datatypes/upload_util.py b/lib/galaxy/datatypes/upload_util.py
index e83400f2c04..1ae447ae9d8 100644
--- a/lib/galaxy/datatypes/upload_util.py
+++ b/lib/galaxy/datatypes/upload_util.py
@@ -1,7 +1,6 @@
import os
from typing import (
NamedTuple,
- Optional,
)
from galaxy.datatypes import (
@@ -16,11 +15,11 @@ class UploadProblemException(Exception):
class HandleUploadResponse(NamedTuple):
- stdout: Optional[str]
+ stdout: str | None
ext: str
datatype: data.Data
is_binary: bool
- converted_path: Optional[str]
+ converted_path: str | None
converted_newlines: bool
converted_spaces: bool
@@ -30,8 +29,8 @@ def handle_upload(
path: str, # dataset.path
requested_ext: str, # dataset.file_type
name: str, # dataset.name,
- tmp_prefix: Optional[str],
- tmp_dir: Optional[str],
+ tmp_prefix: str | None,
+ tmp_dir: str | None,
check_content: bool,
link_data_only: bool,
in_place: bool,
diff --git a/lib/galaxy/dependencies/conditional-requirements.txt b/lib/galaxy/dependencies/conditional-requirements.txt
index 78feb94accb..c349532fd6f 100644
--- a/lib/galaxy/dependencies/conditional-requirements.txt
+++ b/lib/galaxy/dependencies/conditional-requirements.txt
@@ -70,11 +70,7 @@ tensorflow==2.15.1
# Run run.sh or common_startup script with GALAXY_DEPENDENCIES_INSTALL_WEASYPRINT=1
# to install weasyprint as part of Galaxy's conditonal dependency instalation process.
weasyprint>=61.2
-# We pin the transitive weasyprint dependency pydyf here because newer versions are
-# not compatible with the last weasyprint version that still supports python 3.8.
-# This dependency is ignored on python >= 3.9 and should be removed when deprecating
-# support for python 3.8.
-pydyf<0.11; python_version<"3.9"
+
# HTCondor runner — install via `pip install htcondor`; this package provides the `htcondor2` module
htcondor
diff --git a/lib/galaxy/di/__init__.py b/lib/galaxy/di/__init__.py
index d5342e5da2c..614a57018e2 100644
--- a/lib/galaxy/di/__init__.py
+++ b/lib/galaxy/di/__init__.py
@@ -1,7 +1,6 @@
"""Dependency injection framework for Galaxy-type apps."""
from typing import (
- Optional,
TypeVar,
)
@@ -20,7 +19,7 @@ class Container(LagomContainer):
config variables for instance).
"""
- def _register_singleton(self, dep_type: type[T], instance: Optional[T] = None) -> T:
+ def _register_singleton(self, dep_type: type[T], instance: T | None = None) -> T:
if instance is None:
# create an instance from the context and register it as a singleton
instance = self[dep_type]
@@ -28,12 +27,12 @@ class Container(LagomContainer):
return self[dep_type]
def _register_abstract_singleton(
- self, abstract_type: type[T], concrete_type: type[T], instance: Optional[T] = None
+ self, abstract_type: type[T], concrete_type: type[T], instance: T | None = None
) -> T:
self[abstract_type] = instance if instance is not None else concrete_type
return self[abstract_type]
- def resolve_or_none(self, dep_type: type[T]) -> Optional[T]:
+ def resolve_or_none(self, dep_type: type[T]) -> T | None:
"""Resolve the dependent type or just return None.
If resolution is impossible assume caller has a backup plan for
diff --git a/lib/galaxy/exceptions/__init__.py b/lib/galaxy/exceptions/__init__.py
index 55b869558e4..7e542e054bd 100644
--- a/lib/galaxy/exceptions/__init__.py
+++ b/lib/galaxy/exceptions/__init__.py
@@ -16,8 +16,6 @@ have nothing to do with the web - keep this in mind when defining exception name
and messages.
"""
-from typing import Optional
-
from .error_codes import (
error_codes_by_name,
ErrorCode,
@@ -32,7 +30,7 @@ class MessageException(Exception):
# Error code information embedded into API json responses.
err_code: ErrorCode = error_codes_by_name["UNKNOWN"]
- def __init__(self, err_msg: Optional[str] = None, type="info", **extra_error_info):
+ def __init__(self, err_msg: str | None = None, type="info", **extra_error_info):
self.err_msg = err_msg or self.err_code.default_error_message
self.type = type
self.extra_error_info = extra_error_info
@@ -66,7 +64,7 @@ class AcceptedRetryLater(MessageException):
err_code = error_codes_by_name["ACCEPTED_RETRY_LATER"]
retry_after: int
- def __init__(self, msg: Optional[str] = None, retry_after=60):
+ def __init__(self, msg: str | None = None, retry_after=60):
super().__init__(msg)
self.retry_after = retry_after
@@ -138,7 +136,7 @@ class ToolMissingException(MessageException):
status_code = 400
err_code = error_codes_by_name["USER_TOOL_MISSING_PROBLEM"]
- def __init__(self, err_msg: Optional[str] = None, type="info", tool_id=None, **extra_error_info):
+ def __init__(self, err_msg: str | None = None, type="info", tool_id=None, **extra_error_info):
super().__init__(err_msg, type, **extra_error_info)
self.tool_id = tool_id
@@ -155,7 +153,7 @@ class ToolInputsNotReadyException(MessageException):
class ToolInputsNotOKException(MessageException):
def __init__(
- self, err_msg: Optional[str] = None, type="info", *, src: str, id: str, input_name: str, **extra_error_info
+ self, err_msg: str | None = None, type="info", *, src: str, id: str, input_name: str, **extra_error_info
):
super().__init__(err_msg, type, src=src, id=id, input_name=input_name, **extra_error_info)
self.src = src
diff --git a/lib/galaxy/exceptions/error_codes.py b/lib/galaxy/exceptions/error_codes.py
index 0f978bcd4a2..7daed2bcef0 100644
--- a/lib/galaxy/exceptions/error_codes.py
+++ b/lib/galaxy/exceptions/error_codes.py
@@ -4,7 +4,6 @@ See the file error_codes.json for actual error code descriptions.
"""
from json import loads
-from typing import Dict
from galaxy.util.resources import resource_string
@@ -44,8 +43,8 @@ def _from_dict(entry):
error_codes_json = resource_string(__name__, "error_codes.json")
-error_codes_by_name: Dict[str, ErrorCode] = {}
-error_codes_by_int_code: Dict[int, ErrorCode] = {}
+error_codes_by_name: dict[str, ErrorCode] = {}
+error_codes_by_int_code: dict[int, ErrorCode] = {}
for entry in loads(error_codes_json):
name, error_code_obj = _from_dict(entry)
diff --git a/lib/galaxy/exceptions/utils.py b/lib/galaxy/exceptions/utils.py
index b5196f86bb7..725879452cf 100644
--- a/lib/galaxy/exceptions/utils.py
+++ b/lib/galaxy/exceptions/utils.py
@@ -43,8 +43,7 @@ def validation_error_to_message_exception(e: Union["ValidationError", "RequestVa
def api_error_to_dict(**kwds):
UNKNOWN_ERROR_CODE = error_codes.error_codes_by_name["UNKNOWN"]
- exception = kwds.get("exception", None)
- if exception:
+ if exception := kwds.get("exception", None):
# If we are passed a MessageException use err_msg.
default_error_code = getattr(exception, "err_code", UNKNOWN_ERROR_CODE)
default_error_message = getattr(exception, "err_msg", default_error_code.default_error_message)
diff --git a/lib/galaxy/files/__init__.py b/lib/galaxy/files/__init__.py
index 5fccf10f492..77bc0803bcd 100644
--- a/lib/galaxy/files/__init__.py
+++ b/lib/galaxy/files/__init__.py
@@ -6,7 +6,6 @@ from datetime import datetime
from typing import (
Any,
NamedTuple,
- Optional,
Protocol,
)
@@ -55,16 +54,16 @@ class UserDefinedFileSources(Protocol):
def validate_uri_root(self, uri: str, user_context: "FileSourcesUserContext") -> None:
pass
- def find_best_match(self, url: str) -> Optional[FileSourceScore]:
+ def find_best_match(self, url: str) -> FileSourceScore | None:
pass
def user_file_sources_to_dicts(
self,
for_serialization: bool,
user_context: "FileSourcesUserContext",
- browsable_only: Optional[bool] = False,
- include_kind: Optional[set[PluginKind]] = None,
- exclude_kind: Optional[set[PluginKind]] = None,
+ browsable_only: bool | None = False,
+ include_kind: set[PluginKind] | None = None,
+ exclude_kind: set[PluginKind] | None = None,
) -> list[dict[str, Any]]:
"""Write out user file sources as list of config dictionaries."""
# config_dicts: List[FilesSourceProperties] = []
@@ -76,26 +75,25 @@ class UserDefinedFileSources(Protocol):
class NullUserDefinedFileSources(UserDefinedFileSources):
-
def validate_uri_root(self, uri: str, user_context: "FileSourcesUserContext") -> None:
return None
- def find_best_match(self, url: str) -> Optional[FileSourceScore]:
+ def find_best_match(self, url: str) -> FileSourceScore | None:
return None
def user_file_sources_to_dicts(
self,
for_serialization: bool,
user_context: "FileSourcesUserContext",
- browsable_only: Optional[bool] = False,
- include_kind: Optional[set[PluginKind]] = None,
- exclude_kind: Optional[set[PluginKind]] = None,
+ browsable_only: bool | None = False,
+ include_kind: set[PluginKind] | None = None,
+ exclude_kind: set[PluginKind] | None = None,
) -> list[dict[str, Any]]:
return []
def _ensure_user_defined_file_sources(
- user_defined_file_sources: Optional[UserDefinedFileSources] = None,
+ user_defined_file_sources: UserDefinedFileSources | None = None,
) -> UserDefinedFileSources:
if user_defined_file_sources is not None:
return user_defined_file_sources
@@ -104,10 +102,10 @@ def _ensure_user_defined_file_sources(
class ConfiguredFileSourcesConf:
- conf_dict: Optional[PluginConfigsT]
- conf_file: Optional[str]
+ conf_dict: PluginConfigsT | None
+ conf_file: str | None
- def __init__(self, conf_dict: Optional[PluginConfigsT] = None, conf_file: Optional[str] = None):
+ def __init__(self, conf_dict: PluginConfigsT | None = None, conf_file: str | None = None):
self.conf_dict = conf_dict
self.conf_file = conf_file
@@ -131,10 +129,10 @@ class ConfiguredFileSources:
def __init__(
self,
file_sources_config: FileSourcePluginsConfig,
- configured_file_source_conf: Optional[ConfiguredFileSourcesConf] = None,
+ configured_file_source_conf: ConfiguredFileSourcesConf | None = None,
load_stock_plugins: bool = False,
- plugin_loader: Optional[FileSourcePluginLoader] = None,
- user_defined_file_sources: Optional[UserDefinedFileSources] = None,
+ plugin_loader: FileSourcePluginLoader | None = None,
+ user_defined_file_sources: UserDefinedFileSources | None = None,
):
self._file_sources_config = file_sources_config
self._plugin_loader = plugin_loader or FileSourcePluginLoader()
@@ -188,7 +186,7 @@ class ConfiguredFileSources:
def _parse_plugin_source(self, plugin_source: PluginConfigSource):
return self._plugin_loader.load_plugins(plugin_source, self._file_sources_config)
- def find_best_match(self, url: str) -> Optional[BaseFilesSource]:
+ def find_best_match(self, url: str) -> BaseFilesSource | None:
"""Returns the best matching file source for handling a particular url. Each filesource scores its own
ability to match a particular url, and the highest scorer with a score > 0 is selected."""
scores = [FileSourceScore(file_source, file_source.score_url_match(url)) for file_source in self._file_sources]
@@ -256,9 +254,9 @@ class ConfiguredFileSources:
self,
for_serialization: bool = False,
user_context: "OptionalUserContext" = None,
- browsable_only: Optional[bool] = False,
- include_kind: Optional[set[PluginKind]] = None,
- exclude_kind: Optional[set[PluginKind]] = None,
+ browsable_only: bool | None = False,
+ include_kind: set[PluginKind] | None = None,
+ exclude_kind: set[PluginKind] | None = None,
) -> list[dict[str, Any]]:
rval: list[dict[str, Any]] = []
for file_source in self._file_sources:
@@ -322,15 +320,13 @@ class DictifiableFilesSourceContext(Protocol):
@property
def file_sources(self) -> ConfiguredFileSources: ...
- def to_dict(
- self, view: str = "collection", value_mapper: Optional[dict[str, Callable]] = None
- ) -> dict[str, Any]: ...
+ def to_dict(self, view: str = "collection", value_mapper: dict[str, Callable] | None = None) -> dict[str, Any]: ...
class FileSourceDictifiable(Dictifiable, DictifiableFilesSourceContext):
dict_collection_visible_keys = ("email", "username", "ftp_dir", "preferences", "is_admin", "oidc_access_tokens")
- def to_dict(self, view="collection", value_mapper: Optional[dict[str, Callable]] = None) -> dict[str, Any]:
+ def to_dict(self, view="collection", value_mapper: dict[str, Callable] | None = None) -> dict[str, Any]:
rval = super().to_dict(view=view, value_mapper=value_mapper)
rval["role_names"] = list(self.role_names)
rval["group_names"] = list(self.group_names)
@@ -338,15 +334,14 @@ class FileSourceDictifiable(Dictifiable, DictifiableFilesSourceContext):
class FileSourcesUserContext(DictifiableFilesSourceContext, Protocol):
+ @property
+ def email(self) -> str | None: ...
@property
- def email(self) -> Optional[str]: ...
+ def username(self) -> str | None: ...
@property
- def username(self) -> Optional[str]: ...
-
- @property
- def ftp_dir(self) -> Optional[str]: ...
+ def ftp_dir(self) -> str | None: ...
@property
def preferences(self) -> dict[str, Any]: ...
@@ -364,13 +359,13 @@ class FileSourcesUserContext(DictifiableFilesSourceContext, Protocol):
def anonymous(self) -> bool: ...
@property
- def oidc_access_tokens(self) -> Optional[dict[str, str]]: ...
+ def oidc_access_tokens(self) -> dict[str, str] | None: ...
@property
def oidc_access_token_expirations(self) -> dict[str, datetime]: ...
-OptionalUserContext = Optional[FileSourcesUserContext]
+OptionalUserContext = FileSourcesUserContext | None
class ProvidesFileSourcesUserContext(FileSourcesUserContext, FileSourceDictifiable):
@@ -380,12 +375,12 @@ class ProvidesFileSourcesUserContext(FileSourcesUserContext, FileSourceDictifiab
self.trans = trans
@property
- def email(self) -> Optional[str]:
+ def email(self) -> str | None:
user = self.trans.user
return user and user.email
@property
- def username(self) -> Optional[str]:
+ def username(self) -> str | None:
user = self.trans.user
return user and user.username
@@ -439,7 +434,7 @@ class ProvidesFileSourcesUserContext(FileSourcesUserContext, FileSourceDictifiab
return self.trans.anonymous
@property
- def oidc_access_tokens(self) -> Optional[dict[str, str]]:
+ def oidc_access_tokens(self) -> dict[str, str] | None:
"""
Return all available access tokens for the current user.
"""
@@ -477,7 +472,7 @@ class DictFileSourcesUserContext(FileSourcesUserContext, FileSourceDictifiable):
return self._kwd.get("email")
@property
- def username(self) -> Optional[str]:
+ def username(self) -> str | None:
return self._kwd.get("username")
@property
@@ -517,7 +512,7 @@ class DictFileSourcesUserContext(FileSourcesUserContext, FileSourceDictifiable):
return not bool(self._kwd.get("username"))
@property
- def oidc_access_tokens(self) -> Optional[dict[str, str]]:
+ def oidc_access_tokens(self) -> dict[str, str] | None:
return self._kwd.get("oidc_access_tokens")
@property
diff --git a/lib/galaxy/files/models.py b/lib/galaxy/files/models.py
index c970874aab9..5240108e324 100644
--- a/lib/galaxy/files/models.py
+++ b/lib/galaxy/files/models.py
@@ -5,10 +5,8 @@ from typing import (
Any,
Generic,
Literal,
- Optional,
TYPE_CHECKING,
TypeVar,
- Union,
)
from pydantic import (
@@ -47,12 +45,12 @@ class FlexibleModel(BaseModel):
class FileSourcePluginsConfig(BaseModel):
symlink_allowlist: list[str] = []
fetch_url_allowlist: list[IpAllowedListEntryT] = []
- library_import_dir: Optional[str] = None
- user_library_import_dir: Optional[str] = None
- ftp_upload_dir: Optional[str] = None
+ library_import_dir: str | None = None
+ user_library_import_dir: str | None = None
+ ftp_upload_dir: str | None = None
ftp_upload_purge: bool = True
- tmp_dir: Optional[str] = None
- listings_expiry_time: Optional[int] = None
+ tmp_dir: str | None = None
+ listings_expiry_time: int | None = None
@staticmethod
def from_app_config(config):
@@ -104,11 +102,11 @@ class UserData:
self.context = context
@property
- def email(self) -> Optional[str]:
+ def email(self) -> str | None:
return self.context.email if self.context else None
@property
- def username(self) -> Optional[str]:
+ def username(self) -> str | None:
return self.context.username if self.context else None
@property
@@ -150,14 +148,14 @@ class FilesSourceProperties(StrictModel):
),
]
label: Annotated[
- Optional[str],
+ str | None,
Field(
...,
description="The display label for this plugin.",
),
] = None
doc: Annotated[
- Optional[str],
+ str | None,
Field(
title="Documentation",
description="Documentation or extended description for this plugin.",
@@ -180,7 +178,7 @@ class FilesSourceProperties(StrictModel):
),
] = DEFAULT_WRITABLE
requires_roles: Annotated[
- Optional[str],
+ str | None,
Field(
title="Requires roles",
description=(
@@ -192,7 +190,7 @@ class FilesSourceProperties(StrictModel):
),
] = None
requires_groups: Annotated[
- Optional[str],
+ str | None,
Field(
title="Requires groups",
description=(
@@ -204,7 +202,7 @@ class FilesSourceProperties(StrictModel):
),
] = None
oidc_auth_provider: Annotated[
- Optional[str],
+ str | None,
Field(
None,
title="OIDC authorization provider",
@@ -212,7 +210,7 @@ class FilesSourceProperties(StrictModel):
),
] = None
auth_expires_at: Annotated[
- Optional[str],
+ str | None,
Field(
title="Auth expires at",
description=(
@@ -223,7 +221,7 @@ class FilesSourceProperties(StrictModel):
),
] = None
disable_templating: Annotated[
- Optional[bool],
+ bool | None,
Field(
False,
title="Disable Templating",
@@ -234,7 +232,7 @@ class FilesSourceProperties(StrictModel):
),
] = False
scheme: Annotated[
- Optional[str],
+ str | None,
Field(
DEFAULT_SCHEME,
title="Scheme",
@@ -242,7 +240,7 @@ class FilesSourceProperties(StrictModel):
),
] = DEFAULT_SCHEME
uri_root: Annotated[
- Optional[str],
+ str | None,
Field(
title="URI root",
description=(
@@ -252,7 +250,7 @@ class FilesSourceProperties(StrictModel):
),
] = None
url: Annotated[
- Optional[str],
+ str | None,
Field(
title="URL",
description="Optional URL that might be provided by some plugins to link to the remote source.",
@@ -301,7 +299,7 @@ class FilesSourceOptions(StrictModel):
# are merged with constructor defined http_headers. The interpretation of these properties
# are filesystem specific.
extra_props: Annotated[
- Optional[PartialFilesSourceProperties],
+ PartialFilesSourceProperties | None,
Field(
description="Additional properties to override the initial properties defined in the constructor.",
),
@@ -321,7 +319,7 @@ class Entry(FlexibleModel):
name: str
uri: str
# May contain additional properties depending on the file source
- external_link: Optional[str]
+ external_link: str | None
class RemoteEntry(StrictModel):
@@ -344,9 +342,9 @@ class RemoteFileHash(StrictModel):
class RemoteFile(RemoteEntry):
class_: Annotated[Literal["File"], Field(..., serialization_alias="class")] = "File"
size: Annotated[int, Field(..., title="Size", description="The size of the file in bytes.")] = 0
- ctime: Annotated[Optional[str], Field(title="Creation time", description="The creation time of the file.")] = None
+ ctime: Annotated[str | None, Field(title="Creation time", description="The creation time of the file.")] = None
hashes: Annotated[
- Optional[list[RemoteFileHash]],
+ list[RemoteFileHash] | None,
Field(
title="Hashes",
description="List of precomputed hashes for the file, if available.",
@@ -354,7 +352,7 @@ class RemoteFile(RemoteEntry):
] = None
-AnyRemoteEntry = Union[RemoteDirectory, RemoteFile]
+AnyRemoteEntry = RemoteDirectory | RemoteFile
# Fields to skip during template expansion
@@ -385,9 +383,9 @@ class FilesSourceTemplateContext:
def __init__(
self,
- user_data: Optional[UserData] = None,
- environment: Optional[EnvironmentDict] = None,
- file_sources_config: Optional[FileSourcePluginsConfig] = None,
+ user_data: UserData | None = None,
+ environment: EnvironmentDict | None = None,
+ file_sources_config: FileSourcePluginsConfig | None = None,
):
self.user_data = user_data or UserData()
self.environment = environment or {}
diff --git a/lib/galaxy/files/plugins.py b/lib/galaxy/files/plugins.py
index ac2b4db5247..04596c47097 100644
--- a/lib/galaxy/files/plugins.py
+++ b/lib/galaxy/files/plugins.py
@@ -15,7 +15,6 @@ if TYPE_CHECKING:
class FileSourcePluginLoader:
-
def __init__(self):
self._plugin_classes = self._file_source_plugins_dict()
diff --git a/lib/galaxy/files/sources/__init__.py b/lib/galaxy/files/sources/__init__.py
index 1e47033682b..ebcc22bc2fc 100644
--- a/lib/galaxy/files/sources/__init__.py
+++ b/lib/galaxy/files/sources/__init__.py
@@ -11,7 +11,6 @@ from typing import (
Any,
ClassVar,
Generic,
- Optional,
TYPE_CHECKING,
)
@@ -113,7 +112,7 @@ class SingleFileSource(metaclass=abc.ABCMeta):
source_path: str,
native_path: str,
user_context: "OptionalUserContext" = None,
- opts: Optional[FilesSourceOptions] = None,
+ opts: FilesSourceOptions | None = None,
):
"""Realize source path (relative to uri root) to local file system path.
@@ -133,7 +132,7 @@ class SingleFileSource(metaclass=abc.ABCMeta):
target_path: str,
native_path: str,
user_context: "OptionalUserContext" = None,
- opts: Optional[FilesSourceOptions] = None,
+ opts: FilesSourceOptions | None = None,
) -> str:
"""Write file at native path to target_path (relative to uri root).
@@ -218,11 +217,11 @@ class SupportsBrowsing(metaclass=abc.ABCMeta):
path="/",
recursive=False,
user_context: "OptionalUserContext" = None,
- opts: Optional[FilesSourceOptions] = None,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ opts: FilesSourceOptions | None = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
"""Return a list of 'Directory's and 'File's and the total count in a tuple."""
@@ -299,7 +298,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
def get_browsable(self) -> bool:
return file_source_type_is_browsable(type(self))
- def get_prefix(self) -> Optional[str]:
+ def get_prefix(self) -> str | None:
return self.id
def get_scheme(self) -> str:
@@ -332,7 +331,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
root = uri_join(root, prefix)
return root
- def get_url(self) -> Optional[str]:
+ def get_url(self) -> str | None:
"""Returns a URL that can be used to link to the remote source."""
return None
@@ -365,7 +364,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
self.requires_groups = config.requires_groups
self.disable_templating = config.disable_templating
self._validate_security_rules()
- self._auth_expires_at: Optional[datetime] = (
+ self._auth_expires_at: datetime | None = (
datetime.fromisoformat(config.auth_expires_at) if config.auth_expires_at else None
)
@@ -375,7 +374,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
raise FileSourceCredentialExpired()
- def _compute_auth_expires_at(self, user_context: "OptionalUserContext") -> Optional[datetime]:
+ def _compute_auth_expires_at(self, user_context: "OptionalUserContext") -> datetime | None:
if user_context is None:
return None
provider = self.template_config.oidc_auth_provider
@@ -388,7 +387,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
self,
http_headers: dict[str, str],
user_context: "OptionalUserContext",
- ) -> Optional[dict[str, str]]:
+ ) -> dict[str, str] | None:
"""Return a copy of http_headers with a Bearer token added for the configured OIDC provider.
Returns None if no provider is configured, no user context is available, or the user has
@@ -451,7 +450,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
exclude=COMMON_FILE_SOURCE_PROP_NAMES,
)
- def to_dict_time(self, ctime) -> Optional[str]:
+ def to_dict_time(self, ctime) -> str | None:
if ctime is None:
return None
elif isinstance(ctime, (int, float)):
@@ -461,7 +460,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
def _get_runtime_context(
self,
- opts: Optional[FilesSourceOptions] = None,
+ opts: FilesSourceOptions | None = None,
user_context: "OptionalUserContext" = None,
) -> FilesSourceRuntimeContext:
"""
@@ -495,7 +494,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
defaults.update(template_updates)
return self.template_config_class(**defaults)
- def _evaluate_template_config(self, user_data: Optional[UserData] = None) -> TResolvedConfig:
+ def _evaluate_template_config(self, user_data: UserData | None = None) -> TResolvedConfig:
if self.disable_templating:
# Convert template config to resolved config without template evaluation
config_dict = self.template_config.model_dump(exclude_unset=True, exclude_none=True)
@@ -513,11 +512,11 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
path="/",
recursive=False,
user_context: "OptionalUserContext" = None,
- opts: Optional[FilesSourceOptions] = None,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ opts: FilesSourceOptions | None = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
self._check_user_access(user_context)
self._check_credentials_fresh()
@@ -543,10 +542,10 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[builtins.list[AnyRemoteEntry], int]:
raise NotImplementedError()
@@ -554,7 +553,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
self,
entry_data: EntryData,
user_context: "OptionalUserContext" = None,
- opts: Optional[FilesSourceOptions] = None,
+ opts: FilesSourceOptions | None = None,
) -> Entry:
self._ensure_writeable()
self._check_user_access(user_context)
@@ -574,7 +573,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
target_path: str,
native_path: str,
user_context: "OptionalUserContext" = None,
- opts: Optional[FilesSourceOptions] = None,
+ opts: FilesSourceOptions | None = None,
) -> str:
self._ensure_writeable()
self._check_user_access(user_context)
@@ -588,7 +587,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
target_path: str,
native_path: str,
context: FilesSourceRuntimeContext[TResolvedConfig],
- ) -> Optional[str]:
+ ) -> str | None:
pass
def realize_to(
@@ -596,7 +595,7 @@ class BaseFilesSource(FilesSource, Generic[TTemplateConfig, TResolvedConfig]):
source_path: str,
native_path: str,
user_context: "OptionalUserContext" = None,
- opts: Optional[FilesSourceOptions] = None,
+ opts: FilesSourceOptions | None = None,
):
self._check_user_access(user_context)
self._check_credentials_fresh()
diff --git a/lib/galaxy/files/sources/_fsspec.py b/lib/galaxy/files/sources/_fsspec.py
index ae1af1ada31..3c11b197b43 100644
--- a/lib/galaxy/files/sources/_fsspec.py
+++ b/lib/galaxy/files/sources/_fsspec.py
@@ -7,7 +7,6 @@ from typing import (
Any,
cast,
ClassVar,
- Optional,
TypeVar,
)
@@ -55,12 +54,12 @@ class FsspecCommonCacheOptions(StrictModel):
] = True
listings_expiry_time: Annotated[
- Optional[int],
+ int | None,
Field(description="Time in seconds that a listing is considered valid. If None, listings do not expire."),
] = None
max_paths: Annotated[
- Optional[int],
+ int | None,
Field(
description="The number of most recent listings that are considered valid; 'recent' refers to when the entry was set.",
),
@@ -89,7 +88,7 @@ FsspecResolvedConfigurationType = TypeVar("FsspecResolvedConfigurationType", bou
class FsspecFilesSource(BaseFilesSource[FsspecTemplateConfigType, FsspecResolvedConfigurationType]):
- required_module: ClassVar[Optional[type[AbstractFileSystem]]]
+ required_module: ClassVar[type[AbstractFileSystem] | None]
required_package: ClassVar[str]
supports_pagination = True
supports_search = True
@@ -128,10 +127,10 @@ class FsspecFilesSource(BaseFilesSource[FsspecTemplateConfigType, FsspecResolved
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
"""Return the list of 'Directory's and 'File's under the given path.
@@ -215,7 +214,7 @@ class FsspecFilesSource(BaseFilesSource[FsspecTemplateConfigType, FsspecResolved
"""
return path
- def _extract_timestamp(self, info: dict) -> Optional[str]:
+ def _extract_timestamp(self, info: dict) -> str | None:
"""Extract the timestamp from fsspec file info to use it in the RemoteFile entry.
Subclasses can override this to customize timestamp extraction.
@@ -223,13 +222,13 @@ class FsspecFilesSource(BaseFilesSource[FsspecTemplateConfigType, FsspecResolved
"""
return info.get("mtime") or info.get("modified") or info.get("LastModified")
- def _get_formatted_timestamp(self, info: dict) -> Optional[str]:
+ def _get_formatted_timestamp(self, info: dict) -> str | None:
"""Get a formatted timestamp for the RemoteFile entry."""
mtime = self._extract_timestamp(info)
formatted_timestamp = self.to_dict_time(mtime)
return formatted_timestamp
- def _get_file_hashes(self, info: dict) -> Optional[list[RemoteFileHash]]:
+ def _get_file_hashes(self, info: dict) -> list[RemoteFileHash] | None:
"""Get optional file hashes provided by the remote filesystem for the RemoteFile entry.
Subclasses can override this to extract hashes from the file info.
@@ -314,7 +313,7 @@ class FsspecFilesSource(BaseFilesSource[FsspecTemplateConfigType, FsspecResolved
return entries_list
def _apply_pagination(
- self, entries_list: list[AnyRemoteEntry], limit: Optional[int], offset: Optional[int]
+ self, entries_list: list[AnyRemoteEntry], limit: int | None, offset: int | None
) -> list[AnyRemoteEntry]:
"""Apply pagination to the entries list."""
if offset is not None and limit is not None:
diff --git a/lib/galaxy/files/sources/_pyfilesystem2.py b/lib/galaxy/files/sources/_pyfilesystem2.py
index c6bb3a4cb26..7a793a492de 100644
--- a/lib/galaxy/files/sources/_pyfilesystem2.py
+++ b/lib/galaxy/files/sources/_pyfilesystem2.py
@@ -4,7 +4,6 @@ import logging
import os
from typing import (
ClassVar,
- Optional,
)
import fs
@@ -34,7 +33,7 @@ PACKAGE_MESSAGE = "FilesSource plugin is missing required Python PyFilesystem2 p
class PyFilesystem2FilesSource(BaseFilesSource[TTemplateConfig, TResolvedConfig]):
- required_module: ClassVar[Optional[type[FS]]]
+ required_module: ClassVar[type[FS] | None]
required_package: ClassVar[str]
supports_pagination = True
supports_search = True
@@ -62,10 +61,10 @@ class PyFilesystem2FilesSource(BaseFilesSource[TTemplateConfig, TResolvedConfig]
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
"""Return dictionary of 'Directory's and 'File's."""
try:
@@ -95,10 +94,10 @@ class PyFilesystem2FilesSource(BaseFilesSource[TTemplateConfig, TResolvedConfig]
except fs.errors.FSError as e:
raise MessageException(f"Problem listing file source path {path}. Reason: {e}") from e
- def _get_total_matches_count(self, fs: FS, path: str, filter: Optional[list[str]] = None) -> int:
+ def _get_total_matches_count(self, fs: FS, path: str, filter: list[str] | None = None) -> int:
return sum(1 for _ in fs.filterdir(path, namespaces=["basic"], files=filter, dirs=filter))
- def _to_page(self, limit: Optional[int] = None, offset: Optional[int] = None) -> Optional[tuple[int, int]]:
+ def _to_page(self, limit: int | None = None, offset: int | None = None) -> tuple[int, int] | None:
if limit is None and offset is None:
return None
limit = limit or DEFAULT_PAGE_LIMIT
@@ -106,7 +105,7 @@ class PyFilesystem2FilesSource(BaseFilesSource[TTemplateConfig, TResolvedConfig]
end = start + limit
return (start, end)
- def _query_to_filter(self, query: Optional[str]) -> Optional[list[str]]:
+ def _query_to_filter(self, query: str | None) -> list[str] | None:
if not query:
return None
return [f"*{query}*"]
diff --git a/lib/galaxy/files/sources/_rdm.py b/lib/galaxy/files/sources/_rdm.py
index 2a1e3ae3542..a0c0ed0a4ed 100644
--- a/lib/galaxy/files/sources/_rdm.py
+++ b/lib/galaxy/files/sources/_rdm.py
@@ -2,8 +2,6 @@ import logging
from typing import (
Any,
NamedTuple,
- Optional,
- Union,
)
from galaxy.files.models import (
@@ -23,13 +21,13 @@ log = logging.getLogger(__name__)
class RDMFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- token: Optional[Union[str, TemplateExpansion]] = None
- public_name: Optional[Union[str, TemplateExpansion]] = None
+ token: str | TemplateExpansion | None = None
+ public_name: str | TemplateExpansion | None = None
class RDMFileSourceConfiguration(BaseFileSourceConfiguration):
- token: Optional[str] = None
- public_name: Optional[str] = None
+ token: str | None = None
+ public_name: str | None = None
class ContainerAndFileIdentifier(NamedTuple):
@@ -67,7 +65,7 @@ class RDMRepositoryInteractor:
"""
return self._repository_url
- def to_plugin_uri(self, container_id: str, filename: Optional[str] = None) -> str:
+ def to_plugin_uri(self, container_id: str, filename: str | None = None) -> str:
"""Creates a valid plugin URI to reference the given container_id.
If a filename is provided, the URI will reference the specific file in the container."""
@@ -77,10 +75,10 @@ class RDMRepositoryInteractor:
self,
context: FilesSourceRuntimeContext[RDMFileSourceConfiguration],
write_intent: bool,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[RemoteDirectory], int]:
"""Returns the list of file containers in the repository and the total count containers.
@@ -93,7 +91,7 @@ class RDMRepositoryInteractor:
context: FilesSourceRuntimeContext[RDMFileSourceConfiguration],
container_id: str,
writeable: bool,
- query: Optional[str] = None,
+ query: str | None = None,
) -> list[RemoteFile]:
"""Returns the list of files of a file container.
@@ -174,7 +172,7 @@ class RDMFilesSource(BaseFilesSource[RDMFileSourceTemplateConfiguration, RDMFile
def repository(self) -> RDMRepositoryInteractor:
return self._repository_interactor
- def get_url(self) -> Optional[str]:
+ def get_url(self) -> str | None:
return self.template_config.url
def get_repository_interactor(self, repository_url: str) -> RDMRepositoryInteractor:
@@ -194,7 +192,7 @@ class RDMFilesSource(BaseFilesSource[RDMFileSourceTemplateConfiguration, RDMFile
def get_container_id_from_path(self, source_path: str) -> str:
raise NotImplementedError()
- def get_authorization_token(self, context: FilesSourceRuntimeContext[RDMFileSourceConfiguration]) -> Optional[str]:
+ def get_authorization_token(self, context: FilesSourceRuntimeContext[RDMFileSourceConfiguration]) -> str | None:
return context.config.token
def get_public_name(self, context: FilesSourceRuntimeContext[RDMFileSourceConfiguration]) -> str:
diff --git a/lib/galaxy/files/sources/anvil.py b/lib/galaxy/files/sources/anvil.py
index 0dee1425397..90fdc77a1e2 100644
--- a/lib/galaxy/files/sources/anvil.py
+++ b/lib/galaxy/files/sources/anvil.py
@@ -2,10 +2,6 @@ try:
from anvilfs.anvilfs import AnVILFS
except ImportError:
AnVILFS = None
-from typing import (
- Optional,
- Union,
-)
from galaxy.files.models import (
BaseFileSourceConfiguration,
@@ -17,19 +13,19 @@ from ._pyfilesystem2 import PyFilesystem2FilesSource
class AnVILFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- namespace: Union[str, TemplateExpansion]
- workspace: Union[str, TemplateExpansion]
- api_url: Union[str, TemplateExpansion, None] = None
- on_anvil: Union[bool, TemplateExpansion, None] = False
- drs_url: Union[str, TemplateExpansion, None] = None
+ namespace: str | TemplateExpansion
+ workspace: str | TemplateExpansion
+ api_url: str | TemplateExpansion | None = None
+ on_anvil: bool | TemplateExpansion | None = False
+ drs_url: str | TemplateExpansion | None = None
class AnVILFileSourceConfiguration(BaseFileSourceConfiguration):
namespace: str
workspace: str
- api_url: Optional[str] = None
- on_anvil: Optional[bool] = False
- drs_url: Optional[str] = None
+ api_url: str | None = None
+ on_anvil: bool | None = False
+ drs_url: str | None = None
class AnVILFilesSource(PyFilesystem2FilesSource[AnVILFileSourceTemplateConfiguration, AnVILFileSourceConfiguration]):
diff --git a/lib/galaxy/files/sources/ascp.py b/lib/galaxy/files/sources/ascp.py
index 45c7d8d9fa7..5d46e90a778 100644
--- a/lib/galaxy/files/sources/ascp.py
+++ b/lib/galaxy/files/sources/ascp.py
@@ -23,10 +23,6 @@ The implementation is extensible to support future enhancements such as:
"""
import logging
-from typing import (
- Optional,
- Union,
-)
from galaxy.files.models import (
FilesSourceRuntimeContext,
@@ -57,18 +53,18 @@ class AscpFilesSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfigura
but referenced key paths wouldn't be accessible.
"""
- ascp_path: Union[str, TemplateExpansion] = "ascp"
- ssh_key_content: Union[str, TemplateExpansion] # SSH key content as string (required)
- ssh_key_passphrase: Union[str, TemplateExpansion, None] = None # Passphrase for the SSH key (required)
- user: Union[str, TemplateExpansion] # Required field
- host: Union[str, TemplateExpansion] # Required field
- rate_limit: Union[str, TemplateExpansion] = "300m"
- port: Union[int, TemplateExpansion] = 33001
- disable_encryption: Union[bool, TemplateExpansion] = True
- max_retries: Union[int, TemplateExpansion] = 3
- retry_base_delay: Union[float, TemplateExpansion] = 2.0
- retry_max_delay: Union[float, TemplateExpansion] = 60.0
- enable_resume: Union[bool, TemplateExpansion] = True
+ ascp_path: str | TemplateExpansion = "ascp"
+ ssh_key_content: str | TemplateExpansion # SSH key content as string (required)
+ ssh_key_passphrase: str | TemplateExpansion | None = None # Passphrase for the SSH key (required)
+ user: str | TemplateExpansion # Required field
+ host: str | TemplateExpansion # Required field
+ rate_limit: str | TemplateExpansion = "300m"
+ port: int | TemplateExpansion = 33001
+ disable_encryption: bool | TemplateExpansion = True
+ max_retries: int | TemplateExpansion = 3
+ retry_base_delay: float | TemplateExpansion = 2.0
+ retry_max_delay: float | TemplateExpansion = 60.0
+ enable_resume: bool | TemplateExpansion = True
class AscpFilesSourceConfiguration(FsspecBaseFileSourceConfiguration):
@@ -84,7 +80,7 @@ class AscpFilesSourceConfiguration(FsspecBaseFileSourceConfiguration):
ascp_path: str = "ascp"
ssh_key_content: str # SSH key content as string (required)
- ssh_key_passphrase: Optional[str] = None # Passphrase for the SSH key (optional)
+ ssh_key_passphrase: str | None = None # Passphrase for the SSH key (optional)
user: str # Required field
host: str # Required field
rate_limit: str = "300m"
diff --git a/lib/galaxy/files/sources/ascp_fsspec.py b/lib/galaxy/files/sources/ascp_fsspec.py
index 63236d86ead..8c3b1e76259 100644
--- a/lib/galaxy/files/sources/ascp_fsspec.py
+++ b/lib/galaxy/files/sources/ascp_fsspec.py
@@ -13,7 +13,6 @@ import tempfile
import time
from typing import (
Any,
- Optional,
)
from urllib.parse import urlparse
@@ -74,10 +73,10 @@ class AscpFileSystem(AbstractFileSystem):
def __init__(
self,
ssh_key: str,
- ssh_key_passphrase: Optional[str] = None,
+ ssh_key_passphrase: str | None = None,
ascp_path: str = "ascp",
- user: Optional[str] = None,
- host: Optional[str] = None,
+ user: str | None = None,
+ host: str | None = None,
rate_limit: str = "300m",
port: int = 33001,
disable_encryption: bool = True,
diff --git a/lib/galaxy/files/sources/azure.py b/lib/galaxy/files/sources/azure.py
index f90d794a5e0..d40dae6955f 100644
--- a/lib/galaxy/files/sources/azure.py
+++ b/lib/galaxy/files/sources/azure.py
@@ -7,10 +7,6 @@ except ImportError:
BlobFS = None
BlobFSV2 = None
-from typing import (
- Optional,
- Union,
-)
from galaxy.files.models import (
BaseFileSourceConfiguration,
@@ -24,17 +20,17 @@ AzureNamespaceType = Literal["hierarchical", "flat"]
class AzureFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- account_name: Union[str, TemplateExpansion]
- container_name: Union[str, TemplateExpansion]
- account_key: Union[str, TemplateExpansion]
- namespace_type: Optional[AzureNamespaceType] = "hierarchical"
+ account_name: str | TemplateExpansion
+ container_name: str | TemplateExpansion
+ account_key: str | TemplateExpansion
+ namespace_type: AzureNamespaceType | None = "hierarchical"
class AzureFileSourceConfiguration(BaseFileSourceConfiguration):
account_name: str
container_name: str
account_key: str
- namespace_type: Optional[AzureNamespaceType] = "hierarchical"
+ namespace_type: AzureNamespaceType | None = "hierarchical"
class AzureFileSource(PyFilesystem2FilesSource[AzureFileSourceTemplateConfiguration, AzureFileSourceConfiguration]):
diff --git a/lib/galaxy/files/sources/azureflat.py b/lib/galaxy/files/sources/azureflat.py
index 8848196e923..1679fd2db19 100644
--- a/lib/galaxy/files/sources/azureflat.py
+++ b/lib/galaxy/files/sources/azureflat.py
@@ -1,8 +1,4 @@
import logging
-from typing import (
- Optional,
- Union,
-)
from galaxy.files.models import (
AnyRemoteEntry,
@@ -30,14 +26,14 @@ log = logging.getLogger(__name__)
class AzureFlatFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
- account_name: Union[str, TemplateExpansion]
- container_name: Union[str, TemplateExpansion, None] = None
- account_key: Union[str, TemplateExpansion]
+ account_name: str | TemplateExpansion
+ container_name: str | TemplateExpansion | None = None
+ account_key: str | TemplateExpansion
class AzureFlatFileSourceConfiguration(FsspecBaseFileSourceConfiguration):
account_name: str
- container_name: Optional[str] = None
+ container_name: str | None = None
account_key: str
@@ -85,10 +81,10 @@ class AzureFlatFilesSource(
path: str = "/",
recursive: bool = False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
if context.config.container_name is None and path == "/":
fs = self._open_fs(context, {})
diff --git a/lib/galaxy/files/sources/basespace.py b/lib/galaxy/files/sources/basespace.py
index 7c20fd0a775..dd066ccedd5 100644
--- a/lib/galaxy/files/sources/basespace.py
+++ b/lib/galaxy/files/sources/basespace.py
@@ -3,10 +3,6 @@ try:
except ImportError:
BASESPACEFS = None
-from typing import (
- Optional,
- Union,
-)
from galaxy.files.models import (
BaseFileSourceConfiguration,
@@ -18,19 +14,19 @@ from ._pyfilesystem2 import PyFilesystem2FilesSource
class BaseSpaceFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- dir_path: Union[str, TemplateExpansion, None] = "/"
- client_id: Union[str, TemplateExpansion, None] = None
- client_secret: Union[str, TemplateExpansion, None] = None
- access_token: Union[str, TemplateExpansion, None] = None
- basespace_server: Union[str, TemplateExpansion, None] = None
+ dir_path: str | TemplateExpansion | None = "/"
+ client_id: str | TemplateExpansion | None = None
+ client_secret: str | TemplateExpansion | None = None
+ access_token: str | TemplateExpansion | None = None
+ basespace_server: str | TemplateExpansion | None = None
class BaseSpaceFileSourceConfiguration(BaseFileSourceConfiguration):
- dir_path: Optional[str] = "/"
- client_id: Optional[str] = None
- client_secret: Optional[str] = None
- access_token: Optional[str] = None
- basespace_server: Optional[str] = None
+ dir_path: str | None = "/"
+ client_id: str | None = None
+ client_secret: str | None = None
+ access_token: str | None = None
+ basespace_server: str | None = None
class BaseSpaceFilesSource(
diff --git a/lib/galaxy/files/sources/cbioportal.py b/lib/galaxy/files/sources/cbioportal.py
index b85ebc0f91a..fbc5dfa9122 100644
--- a/lib/galaxy/files/sources/cbioportal.py
+++ b/lib/galaxy/files/sources/cbioportal.py
@@ -6,8 +6,6 @@ import tarfile
import urllib.request
from typing import (
Annotated,
- Optional,
- Union,
)
from pydantic import Field
@@ -44,8 +42,8 @@ HTML_TAG_RE = re.compile(r"<[^>]+>")
class CBioPortalFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- api_url: Union[str, TemplateExpansion]
- datahub_url: Union[str, TemplateExpansion]
+ api_url: str | TemplateExpansion
+ datahub_url: str | TemplateExpansion
study_files: list[str] = Field(default_factory=lambda: list(DEFAULT_STUDY_FILES))
@@ -108,10 +106,10 @@ class CBioPortalFilesSource(
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
normalized_path = self._normalize_path(path)
if write_intent:
@@ -276,7 +274,7 @@ class CBioPortalFilesSource(
path = f"/{path}"
return posixpath.normpath(path)
- def _split_study_path(self, path: str) -> tuple[str, Optional[str]]:
+ def _split_study_path(self, path: str) -> tuple[str, str | None]:
parts = self._normalize_path(path).strip("/").split("/")
if len(parts) < 2 or parts[0] != "studies" or not parts[1]:
raise ObjectNotFound(f"Invalid cBioPortal path [{path}]. Expected /studies/[/].")
@@ -287,7 +285,7 @@ class CBioPortalFilesSource(
raise ObjectNotFound(f"Invalid cBioPortal path [{path}]. Expected /studies/[/].")
def _apply_pagination(
- self, entries: list[AnyRemoteEntry], limit: Optional[int], offset: Optional[int]
+ self, entries: list[AnyRemoteEntry], limit: int | None, offset: int | None
) -> list[AnyRemoteEntry]:
if offset is None and limit is None:
return entries
diff --git a/lib/galaxy/files/sources/dataverse.py b/lib/galaxy/files/sources/dataverse.py
index 098db13c6df..c1321fedec2 100644
--- a/lib/galaxy/files/sources/dataverse.py
+++ b/lib/galaxy/files/sources/dataverse.py
@@ -5,7 +5,6 @@ from typing import (
Any,
cast,
get_args,
- Optional,
)
from urllib.error import HTTPError
from urllib.parse import quote
@@ -187,10 +186,10 @@ class DataverseRDMFilesSource(RDMFilesSource):
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
"""This method lists the datasets or files from dataverse."""
is_root_path = path == "/"
@@ -298,7 +297,7 @@ class DataverseRepositoryInteractor(RDMRepositoryInteractor):
def public_dataset_url(self, dataset_id: str) -> str:
return f"{self.repository_url}/dataset.xhtml?persistentId={dataset_id}"
- def to_plugin_uri(self, dataset_id: str, file_identifier: Optional[str] = None) -> str:
+ def to_plugin_uri(self, dataset_id: str, file_identifier: str | None = None) -> str:
"""Build a plugin URI for a dataset or file.
For datasets: dataverse://source/doi:10.70122/FK2/DIG2DG
@@ -330,10 +329,10 @@ class DataverseRepositoryInteractor(RDMRepositoryInteractor):
self,
context: FilesSourceRuntimeContext[RDMFileSourceConfiguration],
write_intent: bool,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[RemoteDirectory], int]:
"""Lists the Dataverse datasets in the repository."""
request_url = self.search_url
@@ -355,7 +354,7 @@ class DataverseRepositoryInteractor(RDMRepositoryInteractor):
context: FilesSourceRuntimeContext[RDMFileSourceConfiguration],
container_id: str,
writeable: bool,
- query: Optional[str] = None,
+ query: str | None = None,
) -> list[RemoteFile]:
"""This method lists the files in a dataverse dataset."""
request_url = self.files_of_dataset_url(dataset_id=container_id)
@@ -364,7 +363,7 @@ class DataverseRepositoryInteractor(RDMRepositoryInteractor):
files = self._filter_files_by_name(files, query)
return files
- def _filter_files_by_name(self, files: list[RemoteFile], query: Optional[str] = None) -> list[RemoteFile]:
+ def _filter_files_by_name(self, files: list[RemoteFile], query: str | None = None) -> list[RemoteFile]:
if not query:
return files
return [file for file in files if query in file.name]
@@ -518,7 +517,7 @@ class DataverseRepositoryInteractor(RDMRepositoryInteractor):
)
return rval
- def _get_file_hashes(self, dataFile: dict) -> Optional[list[RemoteFileHash]]:
+ def _get_file_hashes(self, dataFile: dict) -> list[RemoteFileHash] | None:
hashes: list[RemoteFileHash] = []
# Preferred: extract from "checksum" field
@@ -554,7 +553,7 @@ class DataverseRepositoryInteractor(RDMRepositoryInteractor):
self,
context: FilesSourceRuntimeContext[RDMFileSourceConfiguration],
request_url: str,
- params: Optional[dict[str, Any]] = None,
+ params: dict[str, Any] | None = None,
auth_required: bool = False,
) -> dict:
headers = self._get_request_headers(context, auth_required)
@@ -580,7 +579,7 @@ class DataverseRepositoryInteractor(RDMRepositoryInteractor):
f"Request to {response.url} failed with status code {response.status_code}: {error_message}"
)
- def _raise_auth_required(self, message: Optional[str] = None):
+ def _raise_auth_required(self, message: str | None = None):
raise AuthenticationRequired(
message or f"Please provide a personal access token in your user's preferences for '{self.plugin.label}'"
)
diff --git a/lib/galaxy/files/sources/dropbox.py b/lib/galaxy/files/sources/dropbox.py
index 4a385044ff7..ee564522fac 100644
--- a/lib/galaxy/files/sources/dropbox.py
+++ b/lib/galaxy/files/sources/dropbox.py
@@ -7,8 +7,6 @@ except ImportError:
import posixpath
from typing import (
Annotated,
- Optional,
- Union,
)
from pydantic import (
@@ -40,7 +38,7 @@ AccessTokenField = Field(
class DropboxFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
- access_token: Annotated[Union[str, TemplateExpansion], AccessTokenField]
+ access_token: Annotated[str | TemplateExpansion, AccessTokenField]
class DropboxFilesSourceConfiguration(FsspecBaseFileSourceConfiguration):
@@ -82,7 +80,7 @@ class DropboxFilesSource(FsspecFilesSource[DropboxFileSourceTemplateConfiguratio
return "/"
return filesystem_path if filesystem_path.startswith("/") else f"/{filesystem_path}"
- def _extract_timestamp(self, info: dict) -> Optional[str]:
+ def _extract_timestamp(self, info: dict) -> str | None:
return info.get("server_modified") or info.get("client_modified") or super()._extract_timestamp(info)
def _write_from(
diff --git a/lib/galaxy/files/sources/drs.py b/lib/galaxy/files/sources/drs.py
index 487d6b8f96e..ca6135a0e53 100644
--- a/lib/galaxy/files/sources/drs.py
+++ b/lib/galaxy/files/sources/drs.py
@@ -1,6 +1,5 @@
import logging
import re
-from typing import Union
from galaxy.files.models import (
BaseFileSourceConfiguration,
@@ -20,8 +19,8 @@ log = logging.getLogger(__name__)
class DRSFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
# `url_regex` is not templated because it needs to be set at initialization with no RuntimeContext available.
url_regex: str = r"^drs://"
- force_http: Union[bool, TemplateExpansion] = False
- http_headers: Union[dict[str, str], TemplateExpansion] = {}
+ force_http: bool | TemplateExpansion = False
+ http_headers: dict[str, str] | TemplateExpansion = {}
class DRSFileSourceConfiguration(BaseFileSourceConfiguration):
diff --git a/lib/galaxy/files/sources/elabftw.py b/lib/galaxy/files/sources/elabftw.py
index bef77b7568e..21d70175540 100644
--- a/lib/galaxy/files/sources/elabftw.py
+++ b/lib/galaxy/files/sources/elabftw.py
@@ -62,9 +62,7 @@ from typing import (
Generic,
get_type_hints,
Literal,
- Optional,
TypeVar,
- Union,
)
from urllib.parse import (
ParseResult,
@@ -113,7 +111,7 @@ class eLabFTWRemoteEntryWrapper(Generic[eLabFTWRemoteEntryWrapperType]): # noqa
Wrap a remote entry produced by this module to easily access its entity type, entity id, and attachment id.
"""
- def __init__(self, entry: eLabFTWRemoteEntryWrapperType, source: Optional[dict] = None):
+ def __init__(self, entry: eLabFTWRemoteEntryWrapperType, source: dict | None = None):
"""
Initialize the remote entry wrapper.
@@ -126,27 +124,27 @@ class eLabFTWRemoteEntryWrapper(Generic[eLabFTWRemoteEntryWrapperType]): # noqa
self.source = source
@property
- def entity_type(self) -> Optional[str]:
+ def entity_type(self) -> str | None:
"""
Get the entity type for the wrapped entry.
"""
return self._get_part("entity_type")
@property
- def entity_id(self) -> Optional[str]:
+ def entity_id(self) -> str | None:
"""
Get the entity id for the wrapped entry.
"""
return self._get_part("entity_id")
@property
- def attachment_id(self) -> Optional[str]:
+ def attachment_id(self) -> str | None:
"""
Get the attachment id for the wrapped entry.
"""
return self._get_part("attachment_id")
- def _get_part(self, part: Literal["entity_type", "entity_id", "attachment_id"]) -> Optional[str]:
+ def _get_part(self, part: Literal["entity_type", "entity_id", "attachment_id"]) -> str | None:
"""
Get the entity type, entity id or attachment id for the wrapped entry.
"""
@@ -156,8 +154,8 @@ class eLabFTWRemoteEntryWrapper(Generic[eLabFTWRemoteEntryWrapperType]): # noqa
class eLabFTWFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- endpoint: Union[str, TemplateExpansion]
- api_key: Union[str, TemplateExpansion]
+ endpoint: str | TemplateExpansion
+ api_key: str | TemplateExpansion
class eLabFTWFileSourceConfiguration(BaseFileSourceConfiguration):
@@ -166,7 +164,6 @@ class eLabFTWFileSourceConfiguration(BaseFileSourceConfiguration):
class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration, eLabFTWFileSourceConfiguration]):
-
plugin_type = "elabftw"
plugin_kind = PluginKind.rfs
supports_pagination = False
@@ -178,7 +175,7 @@ class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration,
template_config_class = eLabFTWFileSourceTemplateConfiguration
resolved_config_class = eLabFTWFileSourceConfiguration
- def get_prefix(self) -> Optional[str]:
+ def get_prefix(self) -> str | None:
endpoint: ParseResult = self._get_endpoint()
return self.id if self.scheme not in {"elabftw", DEFAULT_SCHEME} else (endpoint.netloc or None)
# it would make better sense to return
@@ -253,10 +250,10 @@ class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration,
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
# in particular, expecting
# `sort_by: Optional[Literal["name", "uri", "path", "class", "size", "ctime"]] = None,`
# from Python 3.9 on, the following would be possible, although barely readable
@@ -295,10 +292,10 @@ class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration,
context: FilesSourceRuntimeContext[eLabFTWFileSourceConfiguration],
path="/",
recursive=False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
# in particular, expecting
# `sort_by: Optional[Literal["name", "uri", "path", "class", "size", "ctime"]] = None,`
) -> tuple[list[AnyRemoteEntry], int]:
@@ -356,7 +353,6 @@ class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration,
return [value async for value in async_iter]
fetch_entity_types_tasks: list[asyncio.Task] = (
- # fmt: off
[
asyncio.create_task(
collect_async_iterator(
@@ -367,7 +363,6 @@ class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration,
)
)
]
- # fmt: on
if retrieve_entity_types
else []
)
@@ -488,8 +483,11 @@ class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration,
wrapped_entries,
key=lambda x: (
(
- getattr(x.entry, sort_by, constructors[sort_by]()) # fall back to the default object for this key type
- if sort_by is not None else None # fmt: skip
+ getattr(
+ x.entry, sort_by, constructors[sort_by]()
+ ) # fall back to the default object for this key type
+ if sort_by is not None
+ else None
),
x.entry.uri, # ensure deterministic ordering (URIs are unique)
),
@@ -561,10 +559,10 @@ class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration,
entity_type: str,
endpoint: ParseResult,
session: aiohttp.ClientSession,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- order: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ order: str | None = None,
writable: bool = False,
) -> AsyncIterator[eLabFTWRemoteEntryWrapper[RemoteDirectory]]:
"""List an entity type, i.e. either "/experiments" or "/resources"."""
@@ -796,8 +794,7 @@ class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration,
url = urljoin(
f"{endpoint.scheme}://{endpoint.netloc}/",
- f"/api/v2/{entity_type.replace('resources', 'items')}/{entity_id}/uploads/{attachment_id}"
- f"?format=binary",
+ f"/api/v2/{entity_type.replace('resources', 'items')}/{entity_id}/uploads/{attachment_id}?format=binary",
)
try:
with (
@@ -816,7 +813,7 @@ class eLabFTWFilesSource(BaseFilesSource[eLabFTWFileSourceTemplateConfiguration,
raise exception
-def split_path(path: str) -> tuple[Optional[str], Optional[str], Optional[str]]:
+def split_path(path: str) -> tuple[str | None, str | None, str | None]:
"""
Split and validate an eLabFTW path.
@@ -886,16 +883,12 @@ class InvalidPath(
- `attachment_id` is the id (an integer) of an attachment
"""
- message_path_form = (
- # fmt: off
- "path '%' is invalid, paths must be of the form "
- "`/entity_type/entity_id/attachment_id`, where:"
- + dedent("""
+ message_path_form = "path '%' is invalid, paths must be of the form `/entity_type/entity_id/attachment_id`, where:" + dedent(
+ """
- `entity_type` is either 'experiments' or 'resources'
- `entity_id` is the id of an experiment or resource
- `attachment_id` is the id of an attachment
- """[1:])
- # fmt: on
+ """[1:]
)
message_path_absolute = "path '%' is invalid, paths must be absolute"
message_path_entity_type = "path '%' is invalid, paths must start with /experiments or /resources"
diff --git a/lib/galaxy/files/sources/ftp.py b/lib/galaxy/files/sources/ftp.py
index 00d0cd5a2a4..e30cd19ecc0 100644
--- a/lib/galaxy/files/sources/ftp.py
+++ b/lib/galaxy/files/sources/ftp.py
@@ -1,5 +1,4 @@
import urllib.parse
-from typing import Union
try:
from fs.ftpfs import FTPFS
@@ -17,14 +16,14 @@ from ._pyfilesystem2 import PyFilesystem2FilesSource
class FTPFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- host: Union[str, TemplateExpansion] = ""
- port: Union[int, TemplateExpansion] = 21
- user: Union[str, TemplateExpansion] = "anonymous"
- passwd: Union[str, TemplateExpansion] = ""
- acct: Union[str, TemplateExpansion] = ""
- timeout: Union[int, TemplateExpansion] = 10
- proxy: Union[str, TemplateExpansion, None] = None
- tls: Union[bool, TemplateExpansion] = False
+ host: str | TemplateExpansion = ""
+ port: int | TemplateExpansion = 21
+ user: str | TemplateExpansion = "anonymous"
+ passwd: str | TemplateExpansion = ""
+ acct: str | TemplateExpansion = ""
+ timeout: int | TemplateExpansion = 10
+ proxy: str | TemplateExpansion | None = None
+ tls: bool | TemplateExpansion = False
class FTPFileSourceConfiguration(BaseFileSourceConfiguration):
@@ -34,7 +33,7 @@ class FTPFileSourceConfiguration(BaseFileSourceConfiguration):
passwd: str = ""
acct: str = ""
timeout: int = 10
- proxy: Union[str, None] = None
+ proxy: str | None = None
tls: bool = False
diff --git a/lib/galaxy/files/sources/galaxy.py b/lib/galaxy/files/sources/galaxy.py
index 1e3548cd8b8..f160f432b13 100644
--- a/lib/galaxy/files/sources/galaxy.py
+++ b/lib/galaxy/files/sources/galaxy.py
@@ -1,7 +1,5 @@
"""Static Galaxy file sources - ftp and libraries."""
-from typing import Optional
-
from galaxy.files.sources import PluginKind
from .posix import (
PosixFilesSource,
@@ -27,7 +25,7 @@ class UserFtpFilesSource(PosixFilesSource):
# If delete_on_realize is not set, use the default from the file sources config.
self.template_config.delete_on_realize = self.template_config.file_sources_config.ftp_upload_purge
- def get_prefix(self) -> Optional[str]:
+ def get_prefix(self) -> str | None:
return None
def get_scheme(self) -> str:
@@ -48,7 +46,7 @@ class LibraryImportFilesSource(PosixFilesSource):
template_config = self._apply_defaults_to_template(defaults, template_config)
super().__init__(template_config)
- def get_prefix(self) -> Optional[str]:
+ def get_prefix(self) -> str | None:
return None
def get_scheme(self) -> str:
@@ -69,7 +67,7 @@ class UserLibraryImportFilesSource(PosixFilesSource):
template_config = self._apply_defaults_to_template(defaults, template_config)
super().__init__(template_config)
- def get_prefix(self) -> Optional[str]:
+ def get_prefix(self) -> str | None:
return None
def get_scheme(self) -> str:
diff --git a/lib/galaxy/files/sources/googlecloudstorage.py b/lib/galaxy/files/sources/googlecloudstorage.py
index decf322d45a..0bf0475d72f 100644
--- a/lib/galaxy/files/sources/googlecloudstorage.py
+++ b/lib/galaxy/files/sources/googlecloudstorage.py
@@ -1,8 +1,4 @@
import logging
-from typing import (
- Optional,
- Union,
-)
from galaxy.files.models import FilesSourceRuntimeContext
from galaxy.files.sources._fsspec import (
@@ -25,31 +21,31 @@ log = logging.getLogger(__name__)
class GoogleCloudStorageFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
- bucket_name: Union[str, TemplateExpansion]
- root_path: Union[str, TemplateExpansion, None] = None
- project: Union[str, TemplateExpansion, None] = None
- anonymous: Union[bool, TemplateExpansion, None] = True
- service_account_json: Union[str, TemplateExpansion, None] = None
+ bucket_name: str | TemplateExpansion
+ root_path: str | TemplateExpansion | None = None
+ project: str | TemplateExpansion | None = None
+ anonymous: bool | TemplateExpansion | None = True
+ service_account_json: str | TemplateExpansion | None = None
# OAuth credentials
- client_id: Union[str, TemplateExpansion, None] = None
- client_secret: Union[str, TemplateExpansion, None] = None
- token: Union[str, TemplateExpansion, None] = None
- refresh_token: Union[str, TemplateExpansion, None] = None
- token_uri: Union[str, TemplateExpansion, None] = "https://oauth2.googleapis.com/token"
+ client_id: str | TemplateExpansion | None = None
+ client_secret: str | TemplateExpansion | None = None
+ token: str | TemplateExpansion | None = None
+ refresh_token: str | TemplateExpansion | None = None
+ token_uri: str | TemplateExpansion | None = "https://oauth2.googleapis.com/token"
class GoogleCloudStorageFileSourceConfiguration(FsspecBaseFileSourceConfiguration):
bucket_name: str
- root_path: Optional[str] = None
- project: Optional[str] = None
- anonymous: Optional[bool] = True
- service_account_json: Optional[str] = None
+ root_path: str | None = None
+ project: str | None = None
+ anonymous: bool | None = True
+ service_account_json: str | None = None
# OAuth credentials
- client_id: Optional[str] = None
- client_secret: Optional[str] = None
- token: Optional[str] = None
- refresh_token: Optional[str] = None
- token_uri: Optional[str] = "https://oauth2.googleapis.com/token"
+ client_id: str | None = None
+ client_secret: str | None = None
+ token: str | None = None
+ refresh_token: str | None = None
+ token_uri: str | None = "https://oauth2.googleapis.com/token"
class GoogleCloudStorageFilesSource(
@@ -71,7 +67,7 @@ class GoogleCloudStorageFilesSource(
raise self.required_package_exception
config = context.config
- token: Union[str, dict[str, Optional[str]], None]
+ token: str | dict[str, str | None] | None
if config.anonymous:
# Use token='anon' for anonymous access to public buckets
diff --git a/lib/galaxy/files/sources/googledrive.py b/lib/galaxy/files/sources/googledrive.py
index 0b73a253f2a..14b18691536 100644
--- a/lib/galaxy/files/sources/googledrive.py
+++ b/lib/galaxy/files/sources/googledrive.py
@@ -9,8 +9,6 @@ except ImportError:
from datetime import datetime
from typing import (
Annotated,
- Optional,
- Union,
)
from fsspec import AbstractFileSystem
@@ -28,7 +26,7 @@ from ._fsspec import (
FsspecFilesSource,
)
-GalaxyGoogleDriveFileSystem: Optional[type[AbstractFileSystem]]
+GalaxyGoogleDriveFileSystem: type[AbstractFileSystem] | None
if GoogleDriveFileSystem is not None:
@@ -63,7 +61,7 @@ AccessTokenField = Field(
class GoogleDriveFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
- access_token: Annotated[Union[str, TemplateExpansion], AccessTokenField]
+ access_token: Annotated[str | TemplateExpansion, AccessTokenField]
class GoogleDriveFilesSourceConfiguration(FsspecBaseFileSourceConfiguration):
diff --git a/lib/galaxy/files/sources/http.py b/lib/galaxy/files/sources/http.py
index cce94c59110..2ad2865f604 100644
--- a/lib/galaxy/files/sources/http.py
+++ b/lib/galaxy/files/sources/http.py
@@ -1,7 +1,6 @@
import logging
import re
import urllib.request
-from typing import Union
from galaxy.files.models import (
BaseFileSourceConfiguration,
@@ -27,8 +26,8 @@ log = logging.getLogger(__name__)
class HTTPFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
# `url_regex` is not templated because it needs to be set at initialization with no RuntimeContext available.
url_regex: str = r"^https?://|^ftp://"
- http_headers: Union[dict[str, str], TemplateExpansion] = {}
- fetch_url_allowlist: Union[list[IpAllowedListEntryT], TemplateExpansion] = []
+ http_headers: dict[str, str] | TemplateExpansion = {}
+ fetch_url_allowlist: list[IpAllowedListEntryT] | TemplateExpansion = []
class HTTPFileSourceConfiguration(BaseFileSourceConfiguration):
diff --git a/lib/galaxy/files/sources/huggingface.py b/lib/galaxy/files/sources/huggingface.py
index d9aa7b718e6..ecc0ac50381 100644
--- a/lib/galaxy/files/sources/huggingface.py
+++ b/lib/galaxy/files/sources/huggingface.py
@@ -6,8 +6,6 @@ import logging
from typing import (
Annotated,
Literal,
- Optional,
- Union,
)
from fsspec import AbstractFileSystem
@@ -49,14 +47,14 @@ MAX_REPO_LIMIT = 1000
class HuggingFaceFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
token: Annotated[
- Union[str, TemplateExpansion, None],
+ str | TemplateExpansion | None,
Field(
description="Hugging Face API token for accessing private model repositories. "
"If not provided, only public repositories will be accessible.",
),
] = None
endpoint: Annotated[
- Union[str, TemplateExpansion, None],
+ str | TemplateExpansion | None,
Field(
description="Custom endpoint for Hugging Face Hub. "
"If not provided, the default Hugging Face Hub will be used (https://huggingface.co).",
@@ -65,8 +63,8 @@ class HuggingFaceFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateCon
class HuggingFaceFileSourceConfiguration(FsspecBaseFileSourceConfiguration):
- token: Optional[str] = None
- endpoint: Optional[str] = None
+ token: str | None = None
+ endpoint: str | None = None
class HuggingFaceFilesSource(
@@ -102,12 +100,12 @@ class HuggingFaceFilesSource(
# Remove leading slash for HF compatibility
return path.lstrip("/")
- def _extract_timestamp(self, info: dict) -> Optional[str]:
+ def _extract_timestamp(self, info: dict) -> str | None:
"""Extract timestamp from Hugging Face file info to use it in the RemoteFile entry."""
last_commit: dict = info.get("last_commit") or {}
return last_commit.get("date")
- def _get_file_hashes(self, info: dict) -> Optional[list[RemoteFileHash]]:
+ def _get_file_hashes(self, info: dict) -> list[RemoteFileHash] | None:
"""Get optional file hashes provided by Hugging Face for the RemoteFile entry."""
# Files stored in Hugging Face repositories using Git LFS may have SHA-256 hashes.
lfs = info.get("lfs") or {}
@@ -120,10 +118,10 @@ class HuggingFaceFilesSource(
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
# If we're at the root, list repositories using HfApi
if path == "/":
@@ -143,9 +141,9 @@ class HuggingFaceFilesSource(
def _list_repositories(
self,
config: HuggingFaceFileSourceConfiguration,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
if HfApi is None:
raise self.required_package_exception
diff --git a/lib/galaxy/files/sources/iiif.py b/lib/galaxy/files/sources/iiif.py
index fb8f8a863dc..b13b19c374f 100644
--- a/lib/galaxy/files/sources/iiif.py
+++ b/lib/galaxy/files/sources/iiif.py
@@ -1,5 +1,4 @@
import os
-from typing import Union
from fsspec import AbstractFileSystem
@@ -26,7 +25,7 @@ except ImportError:
class IIIFFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
- manifest_url: Union[str, TemplateExpansion]
+ manifest_url: str | TemplateExpansion
class IIIFFileSourceConfiguration(FsspecBaseFileSourceConfiguration):
diff --git a/lib/galaxy/files/sources/invenio.py b/lib/galaxy/files/sources/invenio.py
index 3e4d895ba95..91dc8e18376 100644
--- a/lib/galaxy/files/sources/invenio.py
+++ b/lib/galaxy/files/sources/invenio.py
@@ -6,7 +6,6 @@ from typing import (
Any,
cast,
Literal,
- Optional,
)
from urllib.error import HTTPError
from urllib.parse import quote
@@ -81,7 +80,7 @@ class RecordPersonOrOrg(TypedDict):
class Creator(TypedDict):
person_or_org: RecordPersonOrOrg
- affiliations: Optional[list[AffiliationEntry]]
+ affiliations: list[AffiliationEntry] | None
class RecordMetadata(TypedDict):
@@ -190,10 +189,10 @@ class InvenioRDMFilesSource(RDMFilesSource):
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
is_root_path = path == "/"
if is_root_path:
@@ -254,17 +253,17 @@ class InvenioRepositoryInteractor(RDMRepositoryInteractor):
def user_records_url(self) -> str:
return f"{self.repository_url}/api/user/records"
- def to_plugin_uri(self, record_id: str, filename: Optional[str] = None) -> str:
+ def to_plugin_uri(self, record_id: str, filename: str | None = None) -> str:
return f"{self.plugin.get_uri_root()}/{record_id}{f'/{filename}' if filename else ''}"
def get_file_containers(
self,
context: FilesSourceRuntimeContext[RDMFileSourceConfiguration],
write_intent: bool,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[RemoteDirectory], int]:
"""Gets the records in the repository and returns the total count of records."""
params: dict[str, Any] = {}
@@ -285,7 +284,7 @@ class InvenioRepositoryInteractor(RDMRepositoryInteractor):
total_hits = response_data["hits"]["total"]
return self._get_records_from_response(response_data), total_hits
- def _to_size_page(self, limit: Optional[int], offset: Optional[int]) -> tuple[Optional[int], Optional[int]]:
+ def _to_size_page(self, limit: int | None, offset: int | None) -> tuple[int | None, int | None]:
if limit is None and offset is None:
return None, None
size = limit or DEFAULT_PAGE_LIMIT
@@ -297,7 +296,7 @@ class InvenioRepositoryInteractor(RDMRepositoryInteractor):
context: FilesSourceRuntimeContext[RDMFileSourceConfiguration],
container_id: str,
writeable: bool,
- query: Optional[str] = None,
+ query: str | None = None,
) -> list[RemoteFile]:
conditionally_draft = "/draft" if writeable or self._is_draft_record(container_id, context) else ""
request_url = f"{self.records_url}/{container_id}{conditionally_draft}/files"
@@ -492,7 +491,7 @@ class InvenioRepositoryInteractor(RDMRepositoryInteractor):
)
return rval
- def _get_file_hashes(self, info: dict) -> Optional[list[RemoteFileHash]]:
+ def _get_file_hashes(self, info: dict) -> list[RemoteFileHash] | None:
"""Get optional file hashes provided by InvenioRDM for the RemoteFile entry."""
# InvenioRDM may provide an optional "checksum" field with the file hash.
checksum = info.get("checksum")
@@ -506,7 +505,7 @@ class InvenioRepositoryInteractor(RDMRepositoryInteractor):
return [RemoteFileHash(hash_function=hash_function_name, hash_value=hash_value)]
return None
- def _get_creator_from_public_name(self, public_name: Optional[str] = None) -> Creator:
+ def _get_creator_from_public_name(self, public_name: str | None = None) -> Creator:
given_name = "Anonymous"
family_name = "Galaxy User"
if public_name:
@@ -531,7 +530,7 @@ class InvenioRepositoryInteractor(RDMRepositoryInteractor):
self,
context: FilesSourceRuntimeContext[RDMFileSourceConfiguration],
request_url: str,
- params: Optional[dict[str, Any]] = None,
+ params: dict[str, Any] | None = None,
auth_required: bool = False,
) -> dict:
headers = self._get_request_headers(context, auth_required)
diff --git a/lib/galaxy/files/sources/irods.py b/lib/galaxy/files/sources/irods.py
index 78d649284db..0e05adca307 100644
--- a/lib/galaxy/files/sources/irods.py
+++ b/lib/galaxy/files/sources/irods.py
@@ -1,9 +1,5 @@
import os
from fnmatch import fnmatch
-from typing import (
- Optional,
- Union,
-)
import fs
import fs.errors
@@ -30,23 +26,23 @@ except ImportError:
class IrodsFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- host: Union[str, TemplateExpansion]
- port: Union[int, TemplateExpansion] = 1247
- username: Union[str, TemplateExpansion]
- password: Union[str, TemplateExpansion]
- zone: Union[str, TemplateExpansion]
- root: Optional[Union[str, TemplateExpansion]] = None
- timeout: Union[int, TemplateExpansion] = 30
- refresh_time: Union[int, TemplateExpansion] = 300
- client_server_negotiation: Optional[Union[str, TemplateExpansion]] = None
- client_server_policy: Optional[Union[str, TemplateExpansion]] = None
- encryption_algorithm: Optional[Union[str, TemplateExpansion]] = None
- encryption_key_size: Optional[Union[int, TemplateExpansion]] = None
- encryption_num_hash_rounds: Optional[Union[int, TemplateExpansion]] = None
- encryption_salt_size: Optional[Union[int, TemplateExpansion]] = None
- ssl_verify_server: Optional[Union[str, TemplateExpansion]] = None
- ssl_ca_certificate_file: Optional[Union[str, TemplateExpansion]] = None
- resource: Optional[Union[str, TemplateExpansion]] = None
+ host: str | TemplateExpansion
+ port: int | TemplateExpansion = 1247
+ username: str | TemplateExpansion
+ password: str | TemplateExpansion
+ zone: str | TemplateExpansion
+ root: str | TemplateExpansion | None = None
+ timeout: int | TemplateExpansion = 30
+ refresh_time: int | TemplateExpansion = 300
+ client_server_negotiation: str | TemplateExpansion | None = None
+ client_server_policy: str | TemplateExpansion | None = None
+ encryption_algorithm: str | TemplateExpansion | None = None
+ encryption_key_size: int | TemplateExpansion | None = None
+ encryption_num_hash_rounds: int | TemplateExpansion | None = None
+ encryption_salt_size: int | TemplateExpansion | None = None
+ ssl_verify_server: str | TemplateExpansion | None = None
+ ssl_ca_certificate_file: str | TemplateExpansion | None = None
+ resource: str | TemplateExpansion | None = None
class IrodsFileSourceConfiguration(BaseFileSourceConfiguration):
@@ -55,18 +51,18 @@ class IrodsFileSourceConfiguration(BaseFileSourceConfiguration):
username: str
password: str
zone: str
- root: Optional[str] = None
+ root: str | None = None
timeout: int = 30
refresh_time: int = 300
- client_server_negotiation: Optional[str] = None
- client_server_policy: Optional[str] = None
- encryption_algorithm: Optional[str] = None
- encryption_key_size: Optional[int] = None
- encryption_num_hash_rounds: Optional[int] = None
- encryption_salt_size: Optional[int] = None
- ssl_verify_server: Optional[str] = None
- ssl_ca_certificate_file: Optional[str] = None
- resource: Optional[str] = None
+ client_server_negotiation: str | None = None
+ client_server_policy: str | None = None
+ encryption_algorithm: str | None = None
+ encryption_key_size: int | None = None
+ encryption_num_hash_rounds: int | None = None
+ encryption_salt_size: int | None = None
+ ssl_verify_server: str | None = None
+ ssl_ca_certificate_file: str | None = None
+ resource: str | None = None
class IrodsFilesSource(PyFilesystem2FilesSource[IrodsFileSourceTemplateConfiguration, IrodsFileSourceConfiguration]):
@@ -77,7 +73,7 @@ class IrodsFilesSource(PyFilesystem2FilesSource[IrodsFileSourceTemplateConfigura
template_config_class = IrodsFileSourceTemplateConfiguration
resolved_config_class = IrodsFileSourceConfiguration
- def _iter_directory_entries(self, fs_handle, parent_path: str, normalized_query: Optional[str] = None):
+ def _iter_directory_entries(self, fs_handle, parent_path: str, normalized_query: str | None = None):
for raw_name in fs_handle.listdir(parent_path):
name = os.path.basename(str(raw_name).rstrip("/"))
if not name:
@@ -92,17 +88,16 @@ class IrodsFilesSource(PyFilesystem2FilesSource[IrodsFileSourceTemplateConfigura
self,
fs_handle,
path: str,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
normalized_query = query.lower() if query else None
entries = []
for _, info in self._iter_directory_entries(fs_handle, path, normalized_query):
entries.append(self._resource_info_to_dict(path, info))
count = len(entries)
- page = self._to_page(limit, offset)
- if page is not None:
+ if (page := self._to_page(limit, offset)) is not None:
entries = entries[page[0] : page[1]]
return entries, count
@@ -112,10 +107,10 @@ class IrodsFilesSource(PyFilesystem2FilesSource[IrodsFileSourceTemplateConfigura
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
try:
with self._open_fs(context) as fs_handle:
@@ -150,8 +145,7 @@ class IrodsFilesSource(PyFilesystem2FilesSource[IrodsFileSourceTemplateConfigura
"ssl_verify_server": config.ssl_verify_server,
"ssl_ca_certificate_file": config.ssl_ca_certificate_file,
}
- ssl_context = getattr(config, "ssl_context", None)
- if ssl_context is not None:
+ if (ssl_context := getattr(config, "ssl_context", None)) is not None:
session_kwargs["ssl_context"] = ssl_context
session = iRODSSession(**session_kwargs)
diff --git a/lib/galaxy/files/sources/mavedb.py b/lib/galaxy/files/sources/mavedb.py
index cd70ad1ff63..8f687ba336c 100644
--- a/lib/galaxy/files/sources/mavedb.py
+++ b/lib/galaxy/files/sources/mavedb.py
@@ -1,8 +1,3 @@
-from typing import (
- Optional,
- Union,
-)
-
from galaxy.exceptions import (
AuthenticationRequired,
MessageException,
@@ -29,14 +24,14 @@ except ImportError:
class MaveDBFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
- base_url: Union[str, TemplateExpansion] = DEFAULT_BASE_URL
- api_key: Union[str, TemplateExpansion, None] = None
- timeout: Union[float, TemplateExpansion] = 30.0
+ base_url: str | TemplateExpansion = DEFAULT_BASE_URL
+ api_key: str | TemplateExpansion | None = None
+ timeout: float | TemplateExpansion = 30.0
class MaveDBFileSourceConfiguration(FsspecBaseFileSourceConfiguration):
base_url: str = DEFAULT_BASE_URL
- api_key: Optional[str] = None
+ api_key: str | None = None
timeout: float = 30.0
@@ -71,10 +66,10 @@ class MaveDBFilesSource(FsspecFilesSource[MaveDBFileSourceTemplateConfiguration,
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
collection = path.strip("/")
if recursive or collection not in {"score-sets", "my-score-sets"}:
@@ -105,8 +100,7 @@ class MaveDBFilesSource(FsspecFilesSource[MaveDBFileSourceTemplateConfiguration,
def _info_to_entry(self, info: dict, config: MaveDBFileSourceConfiguration) -> AnyRemoteEntry:
entry = super()._info_to_entry(info, config)
- display_name = info.get("display_name")
- if display_name:
+ if display_name := info.get("display_name"):
entry.name = display_name
return entry
diff --git a/lib/galaxy/files/sources/omero.py b/lib/galaxy/files/sources/omero.py
index 8f4b4fdaf66..21fdcf59651 100644
--- a/lib/galaxy/files/sources/omero.py
+++ b/lib/galaxy/files/sources/omero.py
@@ -4,9 +4,7 @@ from collections.abc import Iterator
from contextlib import contextmanager
from datetime import datetime
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
)
from galaxy.exceptions import (
@@ -47,10 +45,10 @@ OMERO_TMPDIR_FALLBACK = os.path.join(tempfile.gettempdir(), "galaxy", "file_sour
class OmeroFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- username: Union[str, TemplateExpansion]
- password: Union[str, TemplateExpansion]
- host: Union[str, TemplateExpansion]
- port: Union[int, TemplateExpansion]
+ username: str | TemplateExpansion
+ password: str | TemplateExpansion
+ host: str | TemplateExpansion
+ port: int | TemplateExpansion
class OmeroFileSourceConfiguration(BaseFileSourceConfiguration):
@@ -72,7 +70,7 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
def __init__(self, template_config: OmeroFileSourceTemplateConfiguration):
super().__init__(template_config)
- self._configured_omero_tmpdir: Optional[str] = None
+ self._configured_omero_tmpdir: str | None = None
@property
def required_package_exception(self) -> Exception:
@@ -159,10 +157,10 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
"""
List OMERO objects in a hierarchical structure:
@@ -189,9 +187,9 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
self,
omero: BlitzGateway,
path_parts: list[str],
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
) -> list[AnyRemoteEntry]:
"""List entries based on the path depth."""
if len(path_parts) == 0:
@@ -202,7 +200,7 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
return self._list_images(omero, path_parts[0], path_parts[1], limit=limit, offset=offset, query=query)
return []
- def _count_entries_for_path(self, omero: BlitzGateway, path_parts: list[str], query: Optional[str] = None) -> int:
+ def _count_entries_for_path(self, omero: BlitzGateway, path_parts: list[str], query: str | None = None) -> int:
"""Count total entries for pagination without loading all objects."""
if len(path_parts) == 0:
return self._count_projects(omero, query=query)
@@ -212,7 +210,7 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
return self._count_images(omero, path_parts[1], query=query)
return 0
- def _count_projects(self, conn: BlitzGateway, query: Optional[str] = None) -> int:
+ def _count_projects(self, conn: BlitzGateway, query: str | None = None) -> int:
"""Count all projects using efficient HQL query."""
query_service = conn.getQueryService()
params = omero.sys.ParametersI()
@@ -223,7 +221,7 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
result = query_service.projection(hql, params, conn.SERVICE_OPTS)
return result[0][0].val if result else 0
- def _count_datasets(self, conn: BlitzGateway, project_id_str: str, query: Optional[str] = None) -> int:
+ def _count_datasets(self, conn: BlitzGateway, project_id_str: str, query: str | None = None) -> int:
"""Count datasets in a project using efficient HQL query."""
if not project_id_str.startswith("project_"):
return 0
@@ -241,7 +239,7 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
result = query_service.projection(hql, params, conn.SERVICE_OPTS)
return result[0][0].val if result else 0
- def _count_images(self, conn: BlitzGateway, dataset_id_str: str, query: Optional[str] = None) -> int:
+ def _count_images(self, conn: BlitzGateway, dataset_id_str: str, query: str | None = None) -> int:
"""Count images in a dataset using efficient HQL query."""
if not dataset_id_str.startswith("dataset_"):
return 0
@@ -262,9 +260,9 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
def _list_projects(
self,
conn: BlitzGateway,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
) -> list[AnyRemoteEntry]:
"""List all projects as directories at root level."""
if query:
@@ -289,8 +287,8 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
self,
conn: BlitzGateway,
query: str,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
+ limit: int | None = None,
+ offset: int | None = None,
) -> list[AnyRemoteEntry]:
"""List projects matching query using HQL for server-side filtering."""
query_service = conn.getQueryService()
@@ -319,9 +317,9 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
self,
conn: BlitzGateway,
project_id_str: str,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
) -> list[AnyRemoteEntry]:
"""List datasets within a project."""
if not project_id_str.startswith("project_"):
@@ -358,8 +356,8 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
project_id_str: str,
project_id: int,
query: str,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
+ limit: int | None = None,
+ offset: int | None = None,
) -> list[AnyRemoteEntry]:
"""List datasets matching query using HQL for server-side filtering."""
query_service = conn.getQueryService()
@@ -394,9 +392,9 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
conn: BlitzGateway,
project_id_str: str,
dataset_id_str: str,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
) -> list[AnyRemoteEntry]:
"""List images within a dataset."""
if not dataset_id_str.startswith("dataset_"):
@@ -428,8 +426,8 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
dataset_id_str: str,
dataset_id: int,
query: str,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
+ limit: int | None = None,
+ offset: int | None = None,
) -> list[AnyRemoteEntry]:
"""List images matching query using HQL for server-side filtering."""
query_service = conn.getQueryService()
@@ -452,7 +450,7 @@ class OmeroFileSource(BaseFilesSource[OmeroFileSourceTemplateConfiguration, Omer
results.append(self._create_remote_file_for_image(image, image_path))
return results
- def _build_pagination_opts(self, limit: Optional[int] = None, offset: Optional[int] = None) -> dict[str, int]:
+ def _build_pagination_opts(self, limit: int | None = None, offset: int | None = None) -> dict[str, int]:
"""Build OMERO pagination options dictionary."""
opts: dict[str, int] = {}
if limit is not None:
diff --git a/lib/galaxy/files/sources/onedata.py b/lib/galaxy/files/sources/onedata.py
index e5171f9d75e..8630ab37abe 100644
--- a/lib/galaxy/files/sources/onedata.py
+++ b/lib/galaxy/files/sources/onedata.py
@@ -4,8 +4,6 @@ except ImportError:
OnedataRESTFS = None
-from typing import Union
-
from galaxy.files.models import (
BaseFileSourceConfiguration,
BaseFileSourceTemplateConfiguration,
@@ -23,9 +21,9 @@ def remove_prefix(prefix: str, string: str) -> str:
class OnedataFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- access_token: Union[str, TemplateExpansion]
- onezone_domain: Union[str, TemplateExpansion]
- disable_tls_certificate_validation: Union[bool, TemplateExpansion] = False
+ access_token: str | TemplateExpansion
+ onezone_domain: str | TemplateExpansion
+ disable_tls_certificate_validation: bool | TemplateExpansion = False
class OnedataFileSourceConfiguration(BaseFileSourceConfiguration):
diff --git a/lib/galaxy/files/sources/onedrive.py b/lib/galaxy/files/sources/onedrive.py
index 93638458fcc..84880c936d6 100644
--- a/lib/galaxy/files/sources/onedrive.py
+++ b/lib/galaxy/files/sources/onedrive.py
@@ -3,8 +3,6 @@ from __future__ import annotations
from typing import (
Annotated,
Literal,
- Optional,
- Union,
)
from urllib.parse import quote
@@ -43,9 +41,9 @@ DriveMode = Literal["appfolder", "full"]
class OneDriveFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- access_token: Annotated[Union[str, TemplateExpansion], AccessTokenField]
- drive_api_base: Union[str, TemplateExpansion] = "https://graph.microsoft.com/v1.0/me/drive"
- drive_mode: Union[DriveMode, TemplateExpansion] = "appfolder"
+ access_token: Annotated[str | TemplateExpansion, AccessTokenField]
+ drive_api_base: str | TemplateExpansion = "https://graph.microsoft.com/v1.0/me/drive"
+ drive_mode: DriveMode | TemplateExpansion = "appfolder"
class OneDriveFilesSourceConfiguration(BaseFileSourceConfiguration):
@@ -79,8 +77,7 @@ class OneDriveFilesSource(BaseFilesSource[OneDriveFileSourceTemplateConfiguratio
def _item_url(self, config: OneDriveFilesSourceConfiguration, path: str) -> str:
root_url = self._root_url(config)
- encoded_path = self._encoded_path(path)
- if encoded_path:
+ if encoded_path := self._encoded_path(path):
return f"{root_url}:/{encoded_path}"
return root_url
@@ -153,10 +150,10 @@ class OneDriveFilesSource(BaseFilesSource[OneDriveFileSourceTemplateConfiguratio
path: str = "/",
recursive: bool = False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
response = self._request("GET", self._children_url(context.config, path), context)
items = response.json().get("value", [])
diff --git a/lib/galaxy/files/sources/posix.py b/lib/galaxy/files/sources/posix.py
index df9e2e265a6..3baadced2b7 100644
--- a/lib/galaxy/files/sources/posix.py
+++ b/lib/galaxy/files/sources/posix.py
@@ -3,8 +3,6 @@ import os
import shutil
from typing import (
Any,
- Optional,
- Union,
)
from galaxy import exceptions
@@ -33,7 +31,7 @@ DEFAULT_PREFER_LINKS = False
class PosixTemplateConfiguration(BaseFileSourceTemplateConfiguration):
"""Posix template configuration with templating support."""
- root: Union[str, TemplateExpansion, None] = None
+ root: str | TemplateExpansion | None = None
# These are not using TemplateExpansion because they are not user-configurable.
enforce_symlink_security: bool = DEFAULT_ENFORCE_SYMLINK_SECURITY
delete_on_realize: bool = DEFAULT_DELETE_ON_REALIZE
@@ -44,7 +42,7 @@ class PosixTemplateConfiguration(BaseFileSourceTemplateConfiguration):
class PosixConfiguration(BaseFileSourceConfiguration):
"""Posix resolved configuration with proper types."""
- root: Optional[str] = None
+ root: str | None = None
enforce_symlink_security: bool = DEFAULT_ENFORCE_SYMLINK_SECURITY
delete_on_realize: bool = DEFAULT_DELETE_ON_REALIZE
allow_subdir_creation: bool = DEFAULT_ALLOW_SUBDIR_CREATION
@@ -69,7 +67,7 @@ class PosixFilesSource(BaseFilesSource[PosixTemplateConfiguration, PosixConfigur
return self.template_config.prefer_links
@property
- def root(self) -> Optional[str]:
+ def root(self) -> str | None:
"""Return the root directory for backward compatibility."""
return self.template_config.root
@@ -79,10 +77,10 @@ class PosixFilesSource(BaseFilesSource[PosixTemplateConfiguration, PosixConfigur
path="/",
recursive=False,
write_intent: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[list[AnyRemoteEntry], int]:
if not context.config.root:
raise exceptions.ItemAccessibilityException("Listing files at file:// URLs has been disabled.")
diff --git a/lib/galaxy/files/sources/rspace.py b/lib/galaxy/files/sources/rspace.py
index 85458497579..98520e01be9 100644
--- a/lib/galaxy/files/sources/rspace.py
+++ b/lib/galaxy/files/sources/rspace.py
@@ -37,8 +37,6 @@ from typing import (
BinaryIO,
cast,
IO,
- Optional,
- Union,
)
from galaxy.files.models import (
@@ -73,7 +71,7 @@ class FakedNameIO:
having to alter the `rspace-client-python` library itself.
"""
- def __init__(self, handle: IO, name: Optional[str] = None):
+ def __init__(self, handle: IO, name: str | None = None):
"""Initialize the wrapper from an existing file-like object."""
self._handle = handle
self._name = name
@@ -115,7 +113,7 @@ if RSpaceGalleryFilesystem is not None:
self.eln_client.upload_file = MethodType(upload_file, self.eln_client)
- def upload(self, path: str, file: BinaryIO, chunk_size: Optional[int] = None, **options: Any) -> None:
+ def upload(self, path: str, file: BinaryIO, chunk_size: int | None = None, **options: Any) -> None:
"""
Patch the `upload()` method to retrieve the global id from the saved upload response.
"""
@@ -124,8 +122,8 @@ if RSpaceGalleryFilesystem is not None:
class RSpaceFileSourceTemplateConfiguration(BaseFileSourceTemplateConfiguration):
- endpoint: Union[str, TemplateExpansion]
- api_key: Union[str, TemplateExpansion]
+ endpoint: str | TemplateExpansion
+ api_key: str | TemplateExpansion
class RSpaceFileSourceConfiguration(BaseFileSourceConfiguration):
@@ -156,7 +154,7 @@ class RSpaceFilesSource(PyFilesystem2FilesSource[RSpaceFileSourceTemplateConfigu
gallery_fs = PatchedRSpaceGalleryFilesystem(context.config.endpoint, context.config.api_key)
gallery_fs_upload_method = gallery_fs.upload
- def upload(self_, path: str, file: BinaryIO, chunk_size: Optional[int] = None, **options: Any) -> None:
+ def upload(self_, path: str, file: BinaryIO, chunk_size: int | None = None, **options: Any) -> None:
gallery_fs_upload_method(
os.path.dirname(path),
cast(BinaryIO, FakedNameIO(file, name=os.path.basename(path))),
diff --git a/lib/galaxy/files/sources/s3fs.py b/lib/galaxy/files/sources/s3fs.py
index 0a9117426be..f93846c3a8f 100644
--- a/lib/galaxy/files/sources/s3fs.py
+++ b/lib/galaxy/files/sources/s3fs.py
@@ -1,8 +1,4 @@
import logging
-from typing import (
- Optional,
- Union,
-)
from galaxy import exceptions
from galaxy.files.models import FilesSourceRuntimeContext
@@ -28,21 +24,21 @@ log = logging.getLogger(__name__)
class S3FSFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
- anon: Union[bool, TemplateExpansion] = False
- endpoint_url: Union[str, TemplateExpansion, None] = None
- bucket: Union[str, TemplateExpansion, None] = None
- secret: Union[str, TemplateExpansion, None] = None
- key: Union[str, TemplateExpansion, None] = None
- request_checksum_calculation: Union[str, TemplateExpansion, None] = None
+ anon: bool | TemplateExpansion = False
+ endpoint_url: str | TemplateExpansion | None = None
+ bucket: str | TemplateExpansion | None = None
+ secret: str | TemplateExpansion | None = None
+ key: str | TemplateExpansion | None = None
+ request_checksum_calculation: str | TemplateExpansion | None = None
class S3FSFileSourceConfiguration(FsspecBaseFileSourceConfiguration):
anon: bool = False
- endpoint_url: Optional[str] = None
- bucket: Optional[str] = None
- secret: Optional[str] = None
- key: Optional[str] = None
- request_checksum_calculation: Optional[str] = None
+ endpoint_url: str | None = None
+ bucket: str | None = None
+ secret: str | None = None
+ key: str | None = None
+ request_checksum_calculation: str | None = None
class S3FsFilesSource(FsspecFilesSource[S3FSFileSourceTemplateConfiguration, S3FSFileSourceConfiguration]):
diff --git a/lib/galaxy/files/sources/ssh.py b/lib/galaxy/files/sources/ssh.py
index 153ec02bdb6..b354745904c 100644
--- a/lib/galaxy/files/sources/ssh.py
+++ b/lib/galaxy/files/sources/ssh.py
@@ -1,8 +1,6 @@
from io import StringIO
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
)
try:
@@ -28,7 +26,7 @@ from galaxy.files.sources._fsspec import (
from galaxy.util.config_templates import TemplateExpansion
-def _parse_private_key(private_key: str, password: Optional[str]):
+def _parse_private_key(private_key: str, password: str | None):
# Paramiko cannot autodetect the key type, so try the supported key classes.
for pkey_class in (RSAKey, ECDSAKey, Ed25519Key):
try:
@@ -41,21 +39,21 @@ def _parse_private_key(private_key: str, password: Optional[str]):
class SshFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
- host: Union[str, TemplateExpansion]
- user: Optional[Union[str, TemplateExpansion]] = None
- passwd: Optional[Union[str, TemplateExpansion]] = None
- pkey: Optional[Union[str, TemplateExpansion]] = None
- timeout: Union[int, TemplateExpansion] = 10
- port: Union[int, TemplateExpansion] = 22
- compress: Union[bool, TemplateExpansion] = False
- path: Union[str, TemplateExpansion]
+ host: str | TemplateExpansion
+ user: str | TemplateExpansion | None = None
+ passwd: str | TemplateExpansion | None = None
+ pkey: str | TemplateExpansion | None = None
+ timeout: int | TemplateExpansion = 10
+ port: int | TemplateExpansion = 22
+ compress: bool | TemplateExpansion = False
+ path: str | TemplateExpansion
class SshFileSourceConfiguration(FsspecBaseFileSourceConfiguration):
host: str
- user: Optional[str] = None
- passwd: Optional[str] = None
- pkey: Optional[str] = None
+ user: str | None = None
+ passwd: str | None = None
+ pkey: str | None = None
timeout: int = 10
port: int = 22
compress: bool = False
diff --git a/lib/galaxy/files/sources/temp.py b/lib/galaxy/files/sources/temp.py
index cde34762cb5..f6e5ae9d65a 100644
--- a/lib/galaxy/files/sources/temp.py
+++ b/lib/galaxy/files/sources/temp.py
@@ -1,7 +1,6 @@
import os
from typing import (
Annotated,
- Union,
)
from fsspec.implementations.local import LocalFileSystem
@@ -27,7 +26,7 @@ class TempFileSourceCommonProperties(StrictModel):
class TempFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration, TempFileSourceCommonProperties):
- root_path: Union[str, TemplateExpansion]
+ root_path: str | TemplateExpansion
class TempFileSourceConfiguration(FsspecBaseFileSourceConfiguration, TempFileSourceCommonProperties):
diff --git a/lib/galaxy/files/sources/util.py b/lib/galaxy/files/sources/util.py
index 99c49392102..96e79e5e933 100644
--- a/lib/galaxy/files/sources/util.py
+++ b/lib/galaxy/files/sources/util.py
@@ -66,10 +66,10 @@ def _not_implemented(drs_uri: str, desc: str) -> NotImplementedError:
class RetryOptions:
retry_times: int = 5
- override_retry_after: Optional[float] = None
+ override_retry_after: float | None = None
-def retry_and_get(get_url: str, retry_options: RetryOptions, headers: Optional[dict] = None) -> requests.Response:
+def retry_and_get(get_url: str, retry_options: RetryOptions, headers: dict | None = None) -> requests.Response:
response = requests.get(get_url, timeout=DEFAULT_SOCKET_TIMEOUT, headers=headers)
response.raise_for_status()
if response.status_code == 202:
@@ -85,7 +85,7 @@ def retry_and_get(get_url: str, retry_options: RetryOptions, headers: Optional[d
return response
-def _get_access_info(obj_url: str, access_method: dict, headers: Optional[dict] = None) -> tuple[str, dict]:
+def _get_access_info(obj_url: str, access_method: dict, headers: dict | None = None) -> tuple[str, dict]:
# Prefer access_id resolution to get signed/authenticated URLs
if access_method.get("access_id"):
access_id = access_method["access_id"]
@@ -109,7 +109,7 @@ def _get_access_info(obj_url: str, access_method: dict, headers: Optional[dict]
return url, headers_as_dict
-def _download_s3_file(s3_url: str, target_path: StrPath, headers: Optional[dict] = None) -> None:
+def _download_s3_file(s3_url: str, target_path: StrPath, headers: dict | None = None) -> None:
"""Download file from S3 URL directly using s3fs or requests (for signed URLs)."""
try:
# If the URL has query parameters (signed URL), use requests directly
@@ -199,7 +199,7 @@ class CompactIdentifierResolver:
def _cache_result(self, prefix: str, url_pattern: str):
self._cache[prefix] = {"url_pattern": url_pattern, "timestamp": time.time()}
- def _query_identifiers_org(self, prefix: str) -> Optional[str]:
+ def _query_identifiers_org(self, prefix: str) -> str | None:
try:
namespace_url = (
f"https://registry.api.identifiers.org/restApi/namespaces/search/findByPrefix?prefix={prefix}"
@@ -242,7 +242,7 @@ class CompactIdentifierResolver:
return None
- def resolve_prefix(self, prefix: str) -> Optional[str]:
+ def resolve_prefix(self, prefix: str) -> str | None:
if self._is_cached(prefix):
return self._cache[prefix]["url_pattern"]
@@ -281,7 +281,7 @@ def parse_compact_identifier(drs_uri: str) -> tuple[str, str]:
return prefix, accession
-def resolve_compact_identifier_to_url(drs_uri: str, resolver: Optional[CompactIdentifierResolver] = None) -> str:
+def resolve_compact_identifier_to_url(drs_uri: str, resolver: CompactIdentifierResolver | None = None) -> str:
prefix, accession = parse_compact_identifier(drs_uri)
if resolver is None:
@@ -319,11 +319,11 @@ def resolve_compact_identifier_to_url(drs_uri: str, resolver: Optional[CompactId
def fetch_drs_to_file(
drs_uri: str,
target_path: StrPath,
- user_context: Optional[FileSourcesUserContext],
+ user_context: FileSourcesUserContext | None,
force_http=False,
- retry_options: Optional[RetryOptions] = None,
- headers: Optional[dict] = None,
- fetch_url_allowlist: Optional[list[IpAllowedListEntryT]] = None,
+ retry_options: RetryOptions | None = None,
+ headers: dict | None = None,
+ fetch_url_allowlist: list[IpAllowedListEntryT] | None = None,
):
"""Fetch contents of drs:// URI to a target path."""
if not drs_uri.startswith("drs://"):
diff --git a/lib/galaxy/files/sources/webdav.py b/lib/galaxy/files/sources/webdav.py
index f3e72cb1d26..80e9753b57c 100644
--- a/lib/galaxy/files/sources/webdav.py
+++ b/lib/galaxy/files/sources/webdav.py
@@ -1,7 +1,5 @@
from typing import (
Annotated,
- Optional,
- Union,
)
from pydantic import (
@@ -24,14 +22,14 @@ except ImportError:
class WebDavFileSourceTemplateConfiguration(FsspecBaseFileSourceTemplateConfiguration):
- root: Optional[Union[str, TemplateExpansion]] = None
- base_url: Union[str, TemplateExpansion]
- login: Optional[Union[str, TemplateExpansion]] = None
- password: Optional[Union[str, TemplateExpansion]] = None
+ root: str | TemplateExpansion | None = None
+ base_url: str | TemplateExpansion
+ login: str | TemplateExpansion | None = None
+ password: str | TemplateExpansion | None = None
class WebDavFileSourceConfiguration(FsspecBaseFileSourceConfiguration):
- root: Optional[str] = None
+ root: str | None = None
base_url: Annotated[
str,
Field(
@@ -39,8 +37,8 @@ class WebDavFileSourceConfiguration(FsspecBaseFileSourceConfiguration):
description="The fully-qualified WebDAV endpoint URL used to access this file source.",
),
]
- login: Optional[str] = None
- password: Optional[str] = None
+ login: str | None = None
+ password: str | None = None
class WebDavFilesSource(FsspecFilesSource[WebDavFileSourceTemplateConfiguration, WebDavFileSourceConfiguration]):
@@ -52,7 +50,7 @@ class WebDavFilesSource(FsspecFilesSource[WebDavFileSourceTemplateConfiguration,
resolved_config_class = WebDavFileSourceConfiguration
@staticmethod
- def _webdav_endpoint(base_url: str, root: Optional[str]) -> str:
+ def _webdav_endpoint(base_url: str, root: str | None) -> str:
# WebDAV "root" is the service endpoint path (for example Nextcloud's
# /remote.php/dav/files/user), not a directory prefix inside the file source.
base_url = base_url.strip().rstrip("/")
diff --git a/lib/galaxy/files/templates/manager.py b/lib/galaxy/files/templates/manager.py
index 8e573026aec..f5f8dfff735 100644
--- a/lib/galaxy/files/templates/manager.py
+++ b/lib/galaxy/files/templates/manager.py
@@ -1,6 +1,5 @@
import os
from typing import (
- Optional,
Protocol,
)
@@ -26,8 +25,8 @@ SECRETS_NEED_VAULT_MESSAGE = "The file source templates configuration can not be
class AppConfigProtocol(Protocol):
- file_source_templates: Optional[list[RawTemplateConfig]]
- file_source_templates_config_file: Optional[str]
+ file_source_templates: list[RawTemplateConfig] | None
+ file_source_templates_config_file: str | None
class ConfiguredFileSourceTemplates:
diff --git a/lib/galaxy/files/templates/models.py b/lib/galaxy/files/templates/models.py
index fce10849644..1bacee5d070 100644
--- a/lib/galaxy/files/templates/models.py
+++ b/lib/galaxy/files/templates/models.py
@@ -2,8 +2,6 @@ from typing import (
Annotated,
Any,
Literal,
- Optional,
- Union,
)
from pydantic import (
@@ -60,10 +58,10 @@ FileSourceTemplateType = Literal[
class PosixFileSourceTemplateConfiguration(StrictModel):
type: Literal["posix"]
- root: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ root: str | TemplateExpansion
+ writable: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
class PosixFileSourceConfiguration(StrictModel):
@@ -73,17 +71,17 @@ class PosixFileSourceConfiguration(StrictModel):
class OAuth2TemplateConfiguration:
- oauth2_client_id: Union[str, TemplateExpansion]
- oauth2_client_secret: Union[str, TemplateExpansion]
+ oauth2_client_id: str | TemplateExpansion
+ oauth2_client_secret: str | TemplateExpansion
class DropboxFileSourceTemplateConfiguration(OAuth2TemplateConfiguration, StrictModel):
type: Literal["dropbox"]
- writable: Union[bool, TemplateExpansion] = False
- oauth2_client_id: Union[str, TemplateExpansion]
- oauth2_client_secret: Union[str, TemplateExpansion]
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ writable: bool | TemplateExpansion = False
+ oauth2_client_id: str | TemplateExpansion
+ oauth2_client_secret: str | TemplateExpansion
+ template_start: str | None = None
+ template_end: str | None = None
class OAuth2FileSourceConfiguration:
@@ -98,9 +96,9 @@ class DropboxFileSourceConfiguration(OAuth2FileSourceConfiguration, StrictModel)
class GoogleDriveFileSourceTemplateConfiguration(OAuth2TemplateConfiguration, StrictModel):
type: Literal["googledrive"]
- writable: Union[bool, TemplateExpansion] = False
- oauth2_client_id: Union[str, TemplateExpansion]
- oauth2_client_secret: Union[str, TemplateExpansion]
+ writable: bool | TemplateExpansion = False
+ oauth2_client_id: str | TemplateExpansion
+ oauth2_client_secret: str | TemplateExpansion
# Will default to https://www.googleapis.com/auth/drive.file, which provides
# access to a folder specific to your Galaxy instance. Ideally we would use
# https://www.googleapis.com/auth/drive but that would require becoming
@@ -109,9 +107,9 @@ class GoogleDriveFileSourceTemplateConfiguration(OAuth2TemplateConfiguration, St
# work in the context of an open source project like Galaxy, I am
# adding the extension point here for the brave individual that would like
# to use it but I expect it isn't practical for the typical admin.
- oauth2_scope: Optional[Union[str, TemplateExpansion]] = None
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ oauth2_scope: str | TemplateExpansion | None = None
+ template_start: str | None = None
+ template_end: str | None = None
class GoogleDriveFileSourceConfiguration(OAuth2FileSourceConfiguration, StrictModel):
@@ -122,14 +120,14 @@ class GoogleDriveFileSourceConfiguration(OAuth2FileSourceConfiguration, StrictMo
class OneDriveFileSourceTemplateConfiguration(OAuth2TemplateConfiguration, StrictModel):
type: Literal["onedrive"]
- writable: Union[bool, TemplateExpansion] = False
- oauth2_client_id: Union[str, TemplateExpansion]
- oauth2_client_secret: Union[str, TemplateExpansion]
+ writable: bool | TemplateExpansion = False
+ oauth2_client_id: str | TemplateExpansion
+ oauth2_client_secret: str | TemplateExpansion
# Microsoft Graph app-folder scope keeps access limited to Apps/.
- oauth2_scope: Optional[Union[str, TemplateExpansion]] = None
- drive_mode: Union[Literal["appfolder", "full"], TemplateExpansion] = "appfolder"
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ oauth2_scope: str | TemplateExpansion | None = None
+ drive_mode: Literal["appfolder", "full"] | TemplateExpansion = "appfolder"
+ template_start: str | None = None
+ template_end: str | None = None
class OneDriveFileSourceConfiguration(OAuth2FileSourceConfiguration, StrictModel):
@@ -141,71 +139,71 @@ class OneDriveFileSourceConfiguration(OAuth2FileSourceConfiguration, StrictModel
class S3FSFileSourceTemplateConfiguration(StrictModel):
type: Literal["s3fs"]
- endpoint_url: Optional[Union[str, TemplateExpansion]] = None
- anon: Optional[Union[bool, TemplateExpansion]] = False
- secret: Optional[Union[str, TemplateExpansion]] = None
- key: Optional[Union[str, TemplateExpansion]] = None
- bucket: Optional[Union[str, TemplateExpansion]] = None
- writable: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
- request_checksum_calculation: Optional[Union[str, TemplateExpansion, None]] = None
+ endpoint_url: str | TemplateExpansion | None = None
+ anon: bool | TemplateExpansion | None = False
+ secret: str | TemplateExpansion | None = None
+ key: str | TemplateExpansion | None = None
+ bucket: str | TemplateExpansion | None = None
+ writable: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
+ request_checksum_calculation: str | TemplateExpansion | None = None
class S3FSFileSourceConfiguration(StrictModel):
type: Literal["s3fs"]
- endpoint_url: Optional[str] = None
- anon: Optional[bool] = False
- secret: Optional[str] = None
- key: Optional[str] = None
- bucket: Optional[str] = None
+ endpoint_url: str | None = None
+ anon: bool | None = False
+ secret: str | None = None
+ key: str | None = None
+ bucket: str | None = None
writable: bool = False
- request_checksum_calculation: Optional[str] = None
+ request_checksum_calculation: str | None = None
class FtpFileSourceTemplateConfiguration(StrictModel):
type: Literal["ftp"]
- host: Union[str, TemplateExpansion]
- port: Union[int, TemplateExpansion] = 21
- user: Optional[Union[str, TemplateExpansion]] = None
- passwd: Optional[Union[str, TemplateExpansion]] = None
- writable: Union[bool, TemplateExpansion] = False
- tls: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ host: str | TemplateExpansion
+ port: int | TemplateExpansion = 21
+ user: str | TemplateExpansion | None = None
+ passwd: str | TemplateExpansion | None = None
+ writable: bool | TemplateExpansion = False
+ tls: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
class FtpFileSourceConfiguration(StrictModel):
type: Literal["ftp"]
host: str
port: int = 21
- user: Optional[str] = None
- passwd: Optional[str] = None
+ user: str | None = None
+ passwd: str | None = None
writable: bool = False
tls: bool = False
class SshFileSourceTemplateConfiguration(StrictModel):
type: Literal["ssh"]
- host: Union[str, TemplateExpansion]
- user: Optional[Union[str, TemplateExpansion]] = None
- passwd: Optional[Union[str, TemplateExpansion]] = None
- pkey: Optional[Union[str, TemplateExpansion]] = None
- timeout: Union[int, TemplateExpansion] = 10
- port: Union[int, TemplateExpansion] = 22
- compress: Union[bool, TemplateExpansion] = False
- path: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ host: str | TemplateExpansion
+ user: str | TemplateExpansion | None = None
+ passwd: str | TemplateExpansion | None = None
+ pkey: str | TemplateExpansion | None = None
+ timeout: int | TemplateExpansion = 10
+ port: int | TemplateExpansion = 22
+ compress: bool | TemplateExpansion = False
+ path: str | TemplateExpansion
+ writable: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
class SshFileSourceConfiguration(StrictModel):
type: Literal["ssh"]
host: str
- user: Optional[str] = None
- passwd: Optional[str] = None
- pkey: Optional[str] = None
+ user: str | None = None
+ passwd: str | None = None
+ pkey: str | None = None
timeout: int = 10
port: int = 22
compress: bool = False
@@ -215,13 +213,13 @@ class SshFileSourceConfiguration(StrictModel):
class AzureFileSourceTemplateConfiguration(StrictModel):
type: Literal["azure"]
- account_name: Union[str, TemplateExpansion]
- container_name: Union[str, TemplateExpansion]
- account_key: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = False
- namespace_type: Union[str, TemplateExpansion] = "hierarchical"
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ account_name: str | TemplateExpansion
+ container_name: str | TemplateExpansion
+ account_key: str | TemplateExpansion
+ writable: bool | TemplateExpansion = False
+ namespace_type: str | TemplateExpansion = "hierarchical"
+ template_start: str | None = None
+ template_end: str | None = None
class AzureFileSourceConfiguration(StrictModel):
@@ -235,35 +233,35 @@ class AzureFileSourceConfiguration(StrictModel):
class AzureFlatFileSourceTemplateConfiguration(StrictModel):
type: Literal["azureflat"]
- account_name: Union[str, TemplateExpansion]
- container_name: Union[str, TemplateExpansion, None] = None
- account_key: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ account_name: str | TemplateExpansion
+ container_name: str | TemplateExpansion | None = None
+ account_key: str | TemplateExpansion
+ writable: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
class AzureFlatFileSourceConfiguration(StrictModel):
type: Literal["azureflat"]
account_name: str
- container_name: Optional[str] = None
+ container_name: str | None = None
account_key: str
writable: bool = False
class IrodsFileSourceTemplateConfiguration(StrictModel):
type: Literal["irods"]
- host: Union[str, TemplateExpansion]
- port: Union[int, TemplateExpansion] = 1247
- username: Union[str, TemplateExpansion]
- password: Union[str, TemplateExpansion]
- zone: Union[str, TemplateExpansion]
- root: Optional[Union[str, TemplateExpansion]] = None
- timeout: Union[int, TemplateExpansion] = 30
- refresh_time: Union[int, TemplateExpansion] = 300
- writable: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ host: str | TemplateExpansion
+ port: int | TemplateExpansion = 1247
+ username: str | TemplateExpansion
+ password: str | TemplateExpansion
+ zone: str | TemplateExpansion
+ root: str | TemplateExpansion | None = None
+ timeout: int | TemplateExpansion = 30
+ refresh_time: int | TemplateExpansion = 300
+ writable: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
class IrodsFileSourceConfiguration(StrictModel):
@@ -273,7 +271,7 @@ class IrodsFileSourceConfiguration(StrictModel):
username: str
password: str
zone: str
- root: Optional[str] = None
+ root: str | None = None
timeout: int = 30
refresh_time: int = 300
writable: bool = False
@@ -281,12 +279,12 @@ class IrodsFileSourceConfiguration(StrictModel):
class OnedataFileSourceTemplateConfiguration(StrictModel):
type: Literal["onedata"]
- access_token: Union[str, TemplateExpansion]
- onezone_domain: Union[str, TemplateExpansion]
- disable_tls_certificate_validation: Union[bool, TemplateExpansion] = False
- writable: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ access_token: str | TemplateExpansion
+ onezone_domain: str | TemplateExpansion
+ disable_tls_certificate_validation: bool | TemplateExpansion = False
+ writable: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
class OnedataFileSourceConfiguration(StrictModel):
@@ -312,13 +310,13 @@ class WebdavConfigMixin:
class WebdavFileSourceTemplateConfiguration(WebdavConfigMixin, StrictModel):
type: Literal["webdav"]
- base_url: Union[str, TemplateExpansion]
- root: Union[str, TemplateExpansion]
- login: Union[str, TemplateExpansion]
- password: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ base_url: str | TemplateExpansion
+ root: str | TemplateExpansion
+ login: str | TemplateExpansion
+ password: str | TemplateExpansion
+ writable: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
class WebdavFileSourceConfiguration(WebdavConfigMixin, StrictModel):
@@ -332,11 +330,11 @@ class WebdavFileSourceConfiguration(WebdavConfigMixin, StrictModel):
class eLabFTWFileSourceTemplateConfiguration(StrictModel): # noqa
type: Literal["elabftw"]
- endpoint: Union[str, TemplateExpansion]
- api_key: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = True
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ endpoint: str | TemplateExpansion
+ api_key: str | TemplateExpansion
+ writable: bool | TemplateExpansion = True
+ template_start: str | None = None
+ template_end: str | None = None
class eLabFTWFileSourceConfiguration(StrictModel): # noqa
@@ -348,12 +346,12 @@ class eLabFTWFileSourceConfiguration(StrictModel): # noqa
class InvenioFileSourceTemplateConfiguration(StrictModel):
type: Literal["inveniordm"]
- url: Union[str, TemplateExpansion]
- public_name: Union[str, TemplateExpansion]
- token: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = True
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ url: str | TemplateExpansion
+ public_name: str | TemplateExpansion
+ token: str | TemplateExpansion
+ writable: bool | TemplateExpansion = True
+ template_start: str | None = None
+ template_end: str | None = None
class InvenioFileSourceConfiguration(StrictModel):
@@ -366,12 +364,12 @@ class InvenioFileSourceConfiguration(StrictModel):
class ZenodoFileSourceTemplateConfiguration(StrictModel):
type: Literal["zenodo"]
- url: Union[str, TemplateExpansion]
- public_name: Union[str, TemplateExpansion]
- token: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = True
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ url: str | TemplateExpansion
+ public_name: str | TemplateExpansion
+ token: str | TemplateExpansion
+ writable: bool | TemplateExpansion = True
+ template_start: str | None = None
+ template_end: str | None = None
class ZenodoFileSourceConfiguration(StrictModel):
@@ -384,11 +382,11 @@ class ZenodoFileSourceConfiguration(StrictModel):
class RSpaceFileSourceTemplateConfiguration(StrictModel):
type: Literal["rspace"]
- endpoint: Union[str, TemplateExpansion]
- api_key: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = True
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ endpoint: str | TemplateExpansion
+ api_key: str | TemplateExpansion
+ writable: bool | TemplateExpansion = True
+ template_start: str | None = None
+ template_end: str | None = None
class RSpaceFileSourceConfiguration(StrictModel):
@@ -400,12 +398,12 @@ class RSpaceFileSourceConfiguration(StrictModel):
class DataverseFileSourceTemplateConfiguration(StrictModel):
type: Literal["dataverse"]
- url: Union[str, TemplateExpansion]
- public_name: Union[str, TemplateExpansion]
- token: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = True
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ url: str | TemplateExpansion
+ public_name: str | TemplateExpansion
+ token: str | TemplateExpansion
+ writable: bool | TemplateExpansion = True
+ template_start: str | None = None
+ template_end: str | None = None
class DataverseFileSourceConfiguration(StrictModel):
@@ -418,11 +416,11 @@ class DataverseFileSourceConfiguration(StrictModel):
class CBioPortalFileSourceTemplateConfiguration(StrictModel):
type: Literal["cbioportal"]
- api_url: Union[str, TemplateExpansion]
- datahub_url: Union[str, TemplateExpansion]
- writable: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ api_url: str | TemplateExpansion
+ datahub_url: str | TemplateExpansion
+ writable: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
class CBioPortalFileSourceConfiguration(StrictModel):
@@ -434,23 +432,23 @@ class CBioPortalFileSourceConfiguration(StrictModel):
class HuggingFaceFileSourceTemplateConfiguration(StrictModel):
type: Literal["huggingface"]
- token: Union[str, TemplateExpansion, None] = None
- endpoint: Union[str, TemplateExpansion, None] = None
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ token: str | TemplateExpansion | None = None
+ endpoint: str | TemplateExpansion | None = None
+ template_start: str | None = None
+ template_end: str | None = None
class HuggingFaceFileSourceConfiguration(StrictModel):
type: Literal["huggingface"]
- token: Optional[str] = None
- endpoint: Optional[str] = None
+ token: str | None = None
+ endpoint: str | None = None
class IIIFFileSourceTemplateConfiguration(StrictModel):
type: Literal["iiif"]
- manifest_url: Union[str, TemplateExpansion]
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ manifest_url: str | TemplateExpansion
+ template_start: str | None = None
+ template_end: str | None = None
class IIIFFileSourceConfiguration(StrictModel):
@@ -460,29 +458,29 @@ class IIIFFileSourceConfiguration(StrictModel):
class MaveDBFileSourceTemplateConfiguration(StrictModel):
type: Literal["mavedb"]
- base_url: Union[str, TemplateExpansion] = "https://api.mavedb.org/api/v1"
- api_key: Union[str, TemplateExpansion, None] = None
- timeout: Union[float, TemplateExpansion] = 30.0
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ base_url: str | TemplateExpansion = "https://api.mavedb.org/api/v1"
+ api_key: str | TemplateExpansion | None = None
+ timeout: float | TemplateExpansion = 30.0
+ template_start: str | None = None
+ template_end: str | None = None
class MaveDBFileSourceConfiguration(StrictModel):
type: Literal["mavedb"]
base_url: str = "https://api.mavedb.org/api/v1"
- api_key: Optional[str] = None
+ api_key: str | None = None
timeout: float = 30.0
class OmeroFileSourceTemplateConfiguration(StrictModel):
type: Literal["omero"]
- username: Union[str, TemplateExpansion]
- password: Union[str, TemplateExpansion]
- host: Union[str, TemplateExpansion]
- port: Union[int, TemplateExpansion] = 4064
- writable: Union[bool, TemplateExpansion] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ username: str | TemplateExpansion
+ password: str | TemplateExpansion
+ host: str | TemplateExpansion
+ port: int | TemplateExpansion = 4064
+ writable: bool | TemplateExpansion = False
+ template_start: str | None = None
+ template_end: str | None = None
class OmeroFileSourceConfiguration(StrictModel):
@@ -495,58 +493,54 @@ class OmeroFileSourceConfiguration(StrictModel):
FileSourceTemplateConfiguration = Annotated[
- Union[
- PosixFileSourceTemplateConfiguration,
- S3FSFileSourceTemplateConfiguration,
- FtpFileSourceTemplateConfiguration,
- AzureFileSourceTemplateConfiguration,
- AzureFlatFileSourceTemplateConfiguration,
- IrodsFileSourceTemplateConfiguration,
- OnedataFileSourceTemplateConfiguration,
- WebdavFileSourceTemplateConfiguration,
- DropboxFileSourceTemplateConfiguration,
- GoogleDriveFileSourceTemplateConfiguration,
- OneDriveFileSourceTemplateConfiguration,
- eLabFTWFileSourceTemplateConfiguration,
- InvenioFileSourceTemplateConfiguration,
- ZenodoFileSourceTemplateConfiguration,
- RSpaceFileSourceTemplateConfiguration,
- DataverseFileSourceTemplateConfiguration,
- CBioPortalFileSourceTemplateConfiguration,
- HuggingFaceFileSourceTemplateConfiguration,
- IIIFFileSourceTemplateConfiguration,
- MaveDBFileSourceTemplateConfiguration,
- OmeroFileSourceTemplateConfiguration,
- SshFileSourceTemplateConfiguration,
- ],
+ PosixFileSourceTemplateConfiguration
+ | S3FSFileSourceTemplateConfiguration
+ | FtpFileSourceTemplateConfiguration
+ | AzureFileSourceTemplateConfiguration
+ | AzureFlatFileSourceTemplateConfiguration
+ | IrodsFileSourceTemplateConfiguration
+ | OnedataFileSourceTemplateConfiguration
+ | WebdavFileSourceTemplateConfiguration
+ | DropboxFileSourceTemplateConfiguration
+ | GoogleDriveFileSourceTemplateConfiguration
+ | OneDriveFileSourceTemplateConfiguration
+ | eLabFTWFileSourceTemplateConfiguration
+ | InvenioFileSourceTemplateConfiguration
+ | ZenodoFileSourceTemplateConfiguration
+ | RSpaceFileSourceTemplateConfiguration
+ | DataverseFileSourceTemplateConfiguration
+ | CBioPortalFileSourceTemplateConfiguration
+ | HuggingFaceFileSourceTemplateConfiguration
+ | IIIFFileSourceTemplateConfiguration
+ | MaveDBFileSourceTemplateConfiguration
+ | OmeroFileSourceTemplateConfiguration
+ | SshFileSourceTemplateConfiguration,
Field(discriminator="type"),
]
FileSourceConfiguration = Annotated[
- Union[
- PosixFileSourceConfiguration,
- S3FSFileSourceConfiguration,
- FtpFileSourceConfiguration,
- AzureFileSourceConfiguration,
- AzureFlatFileSourceConfiguration,
- IrodsFileSourceConfiguration,
- OnedataFileSourceConfiguration,
- WebdavFileSourceConfiguration,
- DropboxFileSourceConfiguration,
- GoogleDriveFileSourceConfiguration,
- OneDriveFileSourceConfiguration,
- eLabFTWFileSourceConfiguration,
- InvenioFileSourceConfiguration,
- ZenodoFileSourceConfiguration,
- RSpaceFileSourceConfiguration,
- DataverseFileSourceConfiguration,
- CBioPortalFileSourceConfiguration,
- HuggingFaceFileSourceConfiguration,
- IIIFFileSourceConfiguration,
- MaveDBFileSourceConfiguration,
- OmeroFileSourceConfiguration,
- SshFileSourceConfiguration,
- ],
+ PosixFileSourceConfiguration
+ | S3FSFileSourceConfiguration
+ | FtpFileSourceConfiguration
+ | AzureFileSourceConfiguration
+ | AzureFlatFileSourceConfiguration
+ | IrodsFileSourceConfiguration
+ | OnedataFileSourceConfiguration
+ | WebdavFileSourceConfiguration
+ | DropboxFileSourceConfiguration
+ | GoogleDriveFileSourceConfiguration
+ | OneDriveFileSourceConfiguration
+ | eLabFTWFileSourceConfiguration
+ | InvenioFileSourceConfiguration
+ | ZenodoFileSourceConfiguration
+ | RSpaceFileSourceConfiguration
+ | DataverseFileSourceConfiguration
+ | CBioPortalFileSourceConfiguration
+ | HuggingFaceFileSourceConfiguration
+ | IIIFFileSourceConfiguration
+ | MaveDBFileSourceConfiguration
+ | OmeroFileSourceConfiguration
+ | SshFileSourceConfiguration,
Field(discriminator="type"),
]
@@ -559,8 +553,8 @@ class FileSourceTemplateBase(StrictModel):
"""
id: str
- name: Optional[str]
- description: Optional[MarkdownContent]
+ name: str | None
+ description: MarkdownContent | None
# The UI should just show the most recent version but allow
# admins to define newer versions with new parameterizations
# and keep old versions in template catalog for backward compatibility
@@ -570,8 +564,8 @@ class FileSourceTemplateBase(StrictModel):
# template by hiding but keep it in the catalog for backward
# compatibility for users with existing stores of that template.
hidden: bool = False
- variables: Optional[list[TemplateVariable]] = None
- secrets: Optional[list[TemplateSecret]] = None
+ variables: list[TemplateVariable] | None = None
+ secrets: list[TemplateSecret] | None = None
class FileSourceTemplateSummary(FileSourceTemplateBase):
@@ -580,7 +574,7 @@ class FileSourceTemplateSummary(FileSourceTemplateBase):
class FileSourceTemplate(FileSourceTemplateBase):
configuration: FileSourceTemplateConfiguration
- environment: Optional[list[TemplateEnvironmentEntry]] = None
+ environment: list[TemplateEnvironmentEntry] | None = None
@property
def type(self):
@@ -600,7 +594,7 @@ def template_to_configuration(
secrets: SecretsDict,
user_details: UserDetailsDict,
environment: EnvironmentDict,
- implicit: Optional[ImplicitConfigurationParameters] = None,
+ implicit: ImplicitConfigurationParameters | None = None,
) -> FileSourceConfiguration:
configuration_template = template.configuration
populate_default_variables(template.variables, variables)
@@ -660,7 +654,7 @@ def get_oauth2_config(template: FileSourceTemplate) -> OAuth2Configuration:
return get_oauth2_config_from(template, OAUTH2_CONFIGURED_SOURCES)
-def get_oauth2_config_or_none(template: FileSourceTemplate) -> Optional[OAuth2Configuration]:
+def get_oauth2_config_or_none(template: FileSourceTemplate) -> OAuth2Configuration | None:
if template.configuration.type not in OAUTH2_CONFIGURED_SOURCES:
return None
return get_oauth2_config(template)
diff --git a/lib/galaxy/files/unittest_utils/__init__.py b/lib/galaxy/files/unittest_utils/__init__.py
index 2190329505b..d3b344c6861 100644
--- a/lib/galaxy/files/unittest_utils/__init__.py
+++ b/lib/galaxy/files/unittest_utils/__init__.py
@@ -1,6 +1,5 @@
import os
import tempfile
-from typing import Optional
from galaxy.files import (
ConfiguredFileSources,
@@ -10,7 +9,7 @@ from galaxy.files.plugins import FileSourcePluginsConfig
class TestConfiguredFileSources(ConfiguredFileSources):
- def __init__(self, file_sources_config: FileSourcePluginsConfig, conf_dict: dict, test_root: Optional[str]):
+ def __init__(self, file_sources_config: FileSourcePluginsConfig, conf_dict: dict, test_root: str | None):
super().__init__(file_sources_config, ConfiguredFileSourcesConf(conf_dict=conf_dict))
self.test_root = test_root
diff --git a/lib/galaxy/files/uris.py b/lib/galaxy/files/uris.py
index f565de8dad3..89823454439 100644
--- a/lib/galaxy/files/uris.py
+++ b/lib/galaxy/files/uris.py
@@ -40,10 +40,10 @@ def stream_url_to_file(
url: str,
file_sources: Optional["ConfiguredFileSources"] = None,
prefix: str = "gx_file_stream",
- dir: Optional[str] = None,
+ dir: str | None = None,
user_context=None,
- target_path: Optional[str] = None,
- file_source_opts: Optional[FilesSourceOptions] = None,
+ target_path: str | None = None,
+ file_source_opts: FilesSourceOptions | None = None,
) -> str:
file_sources = ensure_file_sources(file_sources)
file_source, rel_path = file_sources.get_file_source_path(url)
diff --git a/lib/galaxy/files/validate/script.py b/lib/galaxy/files/validate/script.py
index d8d1f510084..60c17cdc6e6 100755
--- a/lib/galaxy/files/validate/script.py
+++ b/lib/galaxy/files/validate/script.py
@@ -12,9 +12,6 @@ import argparse
import os
import sys
import traceback
-from typing import (
- Optional,
-)
import yaml
@@ -93,7 +90,7 @@ def parse_arguments():
return parser.parse_args()
-def find_galaxy_config(config_file: Optional[str] = None) -> Optional[str]:
+def find_galaxy_config(config_file: str | None = None) -> str | None:
"""Find the Galaxy configuration file"""
if config_file and os.path.exists(config_file):
return config_file
diff --git a/lib/galaxy/job_execution/datasets.py b/lib/galaxy/job_execution/datasets.py
index 8fb4a6890a5..f6bedc3807e 100644
--- a/lib/galaxy/job_execution/datasets.py
+++ b/lib/galaxy/job_execution/datasets.py
@@ -7,7 +7,6 @@ from abc import (
ABCMeta,
abstractmethod,
)
-from typing import Union
from galaxy.model import (
DatasetCollectionElement,
@@ -15,14 +14,14 @@ from galaxy.model import (
HistoryDatasetCollectionAssociation,
)
-DeferrableObjectsT = Union[
- DatasetInstance,
- HistoryDatasetCollectionAssociation,
- DatasetCollectionElement,
- list[DatasetInstance],
- list[Union[HistoryDatasetCollectionAssociation, DatasetCollectionElement]],
- list[Union[DatasetInstance, HistoryDatasetCollectionAssociation, DatasetCollectionElement]],
-]
+DeferrableObjectsT = (
+ DatasetInstance
+ | HistoryDatasetCollectionAssociation
+ | DatasetCollectionElement
+ | list[DatasetInstance]
+ | list[HistoryDatasetCollectionAssociation | DatasetCollectionElement]
+ | list[DatasetInstance | HistoryDatasetCollectionAssociation | DatasetCollectionElement]
+)
def dataset_path_rewrites(dataset_paths):
diff --git a/lib/galaxy/job_execution/output_collect.py b/lib/galaxy/job_execution/output_collect.py
index 5d3feca5bf0..da4e0b932d5 100644
--- a/lib/galaxy/job_execution/output_collect.py
+++ b/lib/galaxy/job_execution/output_collect.py
@@ -12,7 +12,6 @@ from typing import (
Any,
Optional,
TYPE_CHECKING,
- Union,
)
from galaxy.model import (
@@ -234,7 +233,7 @@ def collect_dynamic_outputs(
class BaseJobContext(ModelPersistenceContext):
final_job_state: "JobState"
- max_discovered_files: Union[int, float]
+ max_discovered_files: int | float
tool_provided_metadata: BaseToolProvidedMetadata
job_working_directory: str
@@ -258,7 +257,7 @@ class BaseJobContext(ModelPersistenceContext):
def change_datatype_actions(self) -> dict[str, Any]: ...
@abc.abstractmethod
- def create_hdca(self, name: str, structure: UninitializedTree) -> Union[HistoryDatasetCollectionAssociation]: ...
+ def create_hdca(self, name: str, structure: UninitializedTree) -> HistoryDatasetCollectionAssociation: ...
@abc.abstractmethod
def get_hdca(self, object_id) -> HistoryDatasetCollectionAssociation: ...
@@ -267,10 +266,10 @@ class BaseJobContext(ModelPersistenceContext):
def get_library_folder(self, destination: dict[str, Any]) -> "LibraryFolder": ...
@abc.abstractmethod
- def output_collection_def(self, name: str) -> Union[None, ToolOutputCollection]: ...
+ def output_collection_def(self, name: str) -> None | ToolOutputCollection: ...
@abc.abstractmethod
- def output_def(self, name: str) -> Union[None, ToolOutput]: ...
+ def output_def(self, name: str) -> None | ToolOutput: ...
class SessionlessJobContext(SessionlessModelPersistenceContext, BaseJobContext):
@@ -280,12 +279,12 @@ class SessionlessJobContext(SessionlessModelPersistenceContext, BaseJobContext):
self,
metadata_params,
tool_provided_metadata: BaseToolProvidedMetadata,
- object_store: Optional[ObjectStore],
+ object_store: ObjectStore | None,
export_store: Optional["DirectoryModelExportStore"],
import_store: "BaseDirectoryImportModelStore",
working_directory: str,
final_job_state: "JobState",
- max_discovered_files: Optional[int],
+ max_discovered_files: int | None,
job: Optional["Job"] = None,
):
# TODO: use a metadata source provider... (pop from inputs and add parameter)
diff --git a/lib/galaxy/job_execution/setup.py b/lib/galaxy/job_execution/setup.py
index c6873300362..c203d70788e 100644
--- a/lib/galaxy/job_execution/setup.py
+++ b/lib/galaxy/job_execution/setup.py
@@ -8,7 +8,6 @@ from typing import (
cast,
NamedTuple,
Optional,
- Union,
)
from galaxy.files import (
@@ -49,8 +48,8 @@ class JobOutput(NamedTuple):
class JobOutputs(threading.local):
def __init__(self) -> None:
super().__init__()
- self.output_hdas_and_paths: Optional[OutputHdasAndType] = None
- self.output_paths: Optional[OutputPaths] = None
+ self.output_hdas_and_paths: OutputHdasAndType | None = None
+ self.output_paths: OutputPaths | None = None
@property
def populated(self) -> bool:
@@ -105,13 +104,13 @@ class JobIO(UsesDictVisibleKeys):
len_file_path: str,
builds_file_path: str,
check_job_script_integrity: bool,
- check_job_script_integrity_count: Optional[int],
- check_job_script_integrity_sleep: Optional[float],
+ check_job_script_integrity_count: int | None,
+ check_job_script_integrity_sleep: float | None,
file_sources_dict: dict[str, Any],
- user_context: Union[FileSourcesUserContext, dict[str, Any]],
- tool_source: Optional[str] = None,
+ user_context: FileSourcesUserContext | dict[str, Any],
+ tool_source: str | None = None,
tool_source_class: Optional["str"] = "XmlToolSource",
- tool_dir: Optional[StrPath] = None,
+ tool_dir: StrPath | None = None,
is_task: bool = False,
):
user_context_instance: FileSourcesUserContext
@@ -144,7 +143,7 @@ class JobIO(UsesDictVisibleKeys):
self.tool_source = tool_source
self.tool_source_class = tool_source_class
self.job_outputs = JobOutputs()
- self._dataset_path_rewriter: Optional[DatasetPathRewriter] = None
+ self._dataset_path_rewriter: DatasetPathRewriter | None = None
@property
def job(self) -> Job:
@@ -217,7 +216,7 @@ class JobIO(UsesDictVisibleKeys):
return filenames
def get_input_datasets(
- self, materialized_objects: Optional[dict[str, DeferrableObjectsT]] = None
+ self, materialized_objects: dict[str, DeferrableObjectsT] | None = None
) -> list[DatasetInstance]:
job = self.job
datasets: list[DatasetInstance] = []
@@ -236,7 +235,7 @@ class JobIO(UsesDictVisibleKeys):
filenames.extend(self.get_input_dataset_fnames(ds))
return filenames
- def get_input_paths(self, materialized_objects: Optional[dict[str, DeferrableObjectsT]]) -> list[DatasetPath]:
+ def get_input_paths(self, materialized_objects: dict[str, DeferrableObjectsT] | None) -> list[DatasetPath]:
paths = []
for ds in self.get_input_datasets(materialized_objects):
paths.append(self.get_input_path(ds))
@@ -313,7 +312,7 @@ class JobIO(UsesDictVisibleKeys):
self.job_outputs.set_job_outputs(job_outputs)
- def get_output_file_id(self, file: str) -> Optional[int]:
+ def get_output_file_id(self, file: str) -> int | None:
for dp in self.output_paths:
if self.outputs_to_working_directory and os.path.basename(dp.false_path) == file:
return dp.dataset_id
diff --git a/lib/galaxy/job_metrics/__init__.py b/lib/galaxy/job_metrics/__init__.py
index 08d3ba0c1ae..181ea721581 100644
--- a/lib/galaxy/job_metrics/__init__.py
+++ b/lib/galaxy/job_metrics/__init__.py
@@ -21,10 +21,7 @@ from abc import (
from typing import (
Any,
cast,
- Dict,
- List,
NamedTuple,
- Optional,
TYPE_CHECKING,
Union,
)
@@ -58,7 +55,7 @@ class DictifiableMetric(NamedTuple):
plugin: str
safety: Safety = Safety.POTENTIALLY_SENSITVE
- def dict(self) -> Dict[str, str]:
+ def dict(self) -> dict[str, str]:
return dict(
title=self.title,
value=self.value,
@@ -79,7 +76,7 @@ class JobMetrics:
def __init__(self, conf_file=None, conf_dict=None, **kwargs):
"""Load :class:`JobInstrumenter` objects from specified configuration file."""
- self.plugin_classes = cast(Dict[str, "InstrumentPlugin"], self.__plugins_dict())
+ self.plugin_classes = cast(dict[str, "InstrumentPlugin"], self.__plugins_dict())
if conf_file and os.path.exists(conf_file):
self.default_job_instrumenter = JobInstrumenter.from_file(self.plugin_classes, conf_file, **kwargs)
elif conf_dict or conf_dict is None:
@@ -101,7 +98,7 @@ class JobMetrics:
assert formatter
return formatter.format(key, value)
- def dictifiable_metrics(self, raw_metrics: List[RawMetric], allowed_safety: Safety) -> List[DictifiableMetric]:
+ def dictifiable_metrics(self, raw_metrics: list[RawMetric], allowed_safety: Safety) -> list[DictifiableMetric]:
def raw_to_dictifiable(raw_metric: RawMetric) -> DictifiableMetric:
metric_name, metric_value, metric_plugin = raw_metric
title, value = self.format(metric_plugin, metric_name, metric_value)
@@ -134,7 +131,7 @@ class JobMetrics:
instrumenter = JobInstrumenter(self.plugin_classes, plugin_source)
self.set_destination_instrumenter(destination_id, instrumenter)
- def set_destination_conf_dicts(self, destination_id: str, conf_dicts: List[Dict[str, Any]]) -> None:
+ def set_destination_conf_dicts(self, destination_id: str, conf_dicts: list[dict[str, Any]]) -> None:
plugin_source = plugin_config.PluginConfigSource("dict", conf_dicts)
instrumenter = JobInstrumenter(self.plugin_classes, plugin_source)
self.set_destination_instrumenter(destination_id, instrumenter)
@@ -157,15 +154,15 @@ class JobMetrics:
class JobInstrumenterI(metaclass=ABCMeta):
@abstractmethod
- def pre_execute_commands(self, job_directory: str) -> Optional[str]:
+ def pre_execute_commands(self, job_directory: str) -> str | None:
return None
@abstractmethod
- def post_execute_commands(self, job_directory: str) -> Optional[str]:
+ def post_execute_commands(self, job_directory: str) -> str | None:
return None
@abstractmethod
- def collect_properties(self, job_id, job_directory: str) -> Dict[str, Any]:
+ def collect_properties(self, job_id, job_directory: str) -> dict[str, Any]:
return {}
@abstractmethod
diff --git a/lib/galaxy/job_metrics/instrumenters/__init__.py b/lib/galaxy/job_metrics/instrumenters/__init__.py
index f60b69679a1..1adaca449bb 100644
--- a/lib/galaxy/job_metrics/instrumenters/__init__.py
+++ b/lib/galaxy/job_metrics/instrumenters/__init__.py
@@ -10,10 +10,6 @@ from abc import (
)
from typing import (
Any,
- Dict,
- List,
- Optional,
- Union,
)
from .. import formatting
@@ -23,13 +19,13 @@ from ..safety import (
)
INSTRUMENT_FILE_PREFIX = "__instrument"
-InstrumentableT = Optional[Union[str, List[str]]]
+InstrumentableT = str | list[str] | None
class InstrumentPlugin(metaclass=ABCMeta):
"""Describes how to instrument job scripts and retrieve collected metrics."""
- formatter: Optional[formatting.JobMetricFormatter] = formatting.JobMetricFormatter()
+ formatter: formatting.JobMetricFormatter | None = formatting.JobMetricFormatter()
default_safety = DEFAULT_SAFETY
@property
@@ -52,7 +48,7 @@ class InstrumentPlugin(metaclass=ABCMeta):
return None
@abstractmethod
- def job_properties(self, job_id, job_directory: str) -> Dict[str, Any]:
+ def job_properties(self, job_id, job_directory: str) -> dict[str, Any]:
"""Collect properties for this plugin from specified job directory.
This method will run on the Galaxy server and can assume files created
in job_directory with pre_execute_instrument and
diff --git a/lib/galaxy/job_metrics/instrumenters/cgroup.py b/lib/galaxy/job_metrics/instrumenters/cgroup.py
index a391686a6ba..cc1b110e494 100644
--- a/lib/galaxy/job_metrics/instrumenters/cgroup.py
+++ b/lib/galaxy/job_metrics/instrumenters/cgroup.py
@@ -4,8 +4,6 @@ import logging
from collections import namedtuple
from typing import (
Any,
- Dict,
- List,
)
from galaxy.util import (
@@ -147,15 +145,15 @@ class CgroupPlugin(InstrumentPlugin):
params = list(DEFAULT_PARAMS)
self.params = params
- def post_execute_instrument(self, job_directory: str) -> List[str]:
- commands: List[str] = []
+ def post_execute_instrument(self, job_directory: str) -> list[str]:
+ commands: list[str] = []
if self.version in ("auto", "1"):
commands.append(self.__record_cgroup_v1_usage(job_directory))
if self.version in ("auto", "2"):
commands.append(self.__record_cgroup_v2_usage(job_directory))
return commands
- def job_properties(self, job_id, job_directory: str) -> Dict[str, Any]:
+ def job_properties(self, job_id, job_directory: str) -> dict[str, Any]:
metrics = self.__read_metrics(self.__cgroup_metrics_file(job_directory))
return metrics
@@ -173,7 +171,7 @@ class CgroupPlugin(InstrumentPlugin):
return self._instrument_file_path(job_directory, "_metrics")
def __read_metrics(self, path):
- metrics: Dict[str, str] = {}
+ metrics: dict[str, str] = {}
key = None
with open(path) as infile:
for line in infile:
diff --git a/lib/galaxy/job_metrics/instrumenters/core.py b/lib/galaxy/job_metrics/instrumenters/core.py
index cd9e94f968d..c10ad33ec2f 100644
--- a/lib/galaxy/job_metrics/instrumenters/core.py
+++ b/lib/galaxy/job_metrics/instrumenters/core.py
@@ -5,9 +5,6 @@ import json
import logging
from typing import (
Any,
- Dict,
- List,
- Optional,
)
from . import InstrumentPlugin
@@ -36,12 +33,12 @@ CONTAINER_TYPE = "container_type"
class CorePluginFormatter(JobMetricFormatter):
- def __init__(self, timezone: Optional[str]):
- self.tz: Optional[zoneinfo.ZoneInfo] = None
+ def __init__(self, timezone: str | None):
+ self.tz: zoneinfo.ZoneInfo | None = None
self.strftime_format = "%Y-%m-%d %H:%M:%S"
self.__init_tz(timezone)
- def __init_tz(self, timezone: Optional[str]):
+ def __init_tz(self, timezone: str | None):
if timezone:
self.tz = zoneinfo.ZoneInfo(timezone)
self.strftime_format = "%Y-%m-%d %H:%M:%S %Z (%z)"
@@ -76,23 +73,23 @@ class CorePlugin(InstrumentPlugin):
def __init__(self, **kwargs):
self.__init_formatter(kwargs.get("timezone"))
- def __init_formatter(self, timezone: Optional[str]):
+ def __init_formatter(self, timezone: str | None):
if CorePlugin.formatter is None:
CorePlugin.formatter = CorePluginFormatter(timezone)
- def pre_execute_instrument(self, job_directory: str) -> List[str]:
+ def pre_execute_instrument(self, job_directory: str) -> list[str]:
commands = []
commands.append(self.__record_galaxy_slots_command(job_directory))
commands.append(self.__record_galaxy_memory_mb_command(job_directory))
commands.append(self.__record_seconds_since_epoch_to_file(job_directory, "start"))
return commands
- def post_execute_instrument(self, job_directory: str) -> List[str]:
+ def post_execute_instrument(self, job_directory: str) -> list[str]:
commands = []
commands.append(self.__record_seconds_since_epoch_to_file(job_directory, "end"))
return commands
- def job_properties(self, job_id, job_directory: str) -> Dict[str, Any]:
+ def job_properties(self, job_id, job_directory: str) -> dict[str, Any]:
galaxy_slots_file = self.__galaxy_slots_file(job_directory)
galaxy_memory_mb_file = self.__galaxy_memory_mb_file(job_directory)
@@ -111,7 +108,7 @@ class CorePlugin(InstrumentPlugin):
def get_container_file_path(self, job_directory):
return self._instrument_file_path(job_directory, "container")
- def __read_container_details(self, job_directory) -> Dict[str, str]:
+ def __read_container_details(self, job_directory) -> dict[str, str]:
try:
with open(self.get_container_file_path(job_directory)) as fh:
return json.load(fh)
diff --git a/lib/galaxy/job_metrics/instrumenters/env.py b/lib/galaxy/job_metrics/instrumenters/env.py
index e58b4b31d8b..466f3ac1672 100644
--- a/lib/galaxy/job_metrics/instrumenters/env.py
+++ b/lib/galaxy/job_metrics/instrumenters/env.py
@@ -2,10 +2,6 @@
import logging
import re
-from typing import (
- List,
- Optional,
-)
from . import InstrumentPlugin
from ..formatting import JobMetricFormatter
@@ -25,7 +21,7 @@ class EnvPlugin(InstrumentPlugin):
plugin_type = "env"
formatter = EnvFormatter()
- variables: Optional[List[str]]
+ variables: list[str] | None
default_safety = Safety.UNSAFE
def __init__(self, **kwargs):
diff --git a/lib/galaxy/jobs/__init__.py b/lib/galaxy/jobs/__init__.py
index 31b756e6690..a3e058c4e4c 100644
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -30,7 +30,6 @@ from typing import (
Optional,
TYPE_CHECKING,
TypedDict,
- Union,
)
import yaml
@@ -140,10 +139,10 @@ VALID_TOOL_CLASSES = ["local", "requires_galaxy", "user_defined"]
class ResubmitConfigDict(TypedDict, total=False):
- environment: Union[str, None]
- condition: Union[str, None]
- handler: Union[str, None]
- delay: Union[str, None]
+ environment: str | None
+ condition: str | None
+ handler: str | None
+ delay: str | None
class JobToolConfiguration(Bunch):
@@ -210,7 +209,7 @@ def job_config_xml_to_dict(config, root: "Element") -> dict[str, Any]:
environment: dict[str, Any] = {"id": destination_id}
- metrics_to_dict: dict[str, Union[str, Element]] = {"src": "default"}
+ metrics_to_dict: dict[str, str | Element] = {"src": "default"}
if destination_metrics:
if not util.asbool(destination_metrics):
metrics_to_dict = {"src": "disabled"}
@@ -295,7 +294,7 @@ def job_config_xml_to_dict(config, root: "Element") -> dict[str, Any]:
value = limit.get(key)
if value:
if key == "type" and value.startswith("destination_"):
- value = f"environment_{value[len('destination_'):]}"
+ value = f"environment_{value[len('destination_') :]}"
limit_dict[key] = value
limits_config.append(limit_dict)
@@ -305,12 +304,12 @@ def job_config_xml_to_dict(config, root: "Element") -> dict[str, Any]:
@dataclass
class JobConfigurationLimits:
- registered_user_concurrent_jobs: Optional[int] = None
- anonymous_user_concurrent_jobs: Optional[int] = None
- walltime: Optional[str] = None
- walltime_delta: Optional[datetime.timedelta] = None
+ registered_user_concurrent_jobs: int | None = None
+ anonymous_user_concurrent_jobs: int | None = None
+ walltime: str | None = None
+ walltime_delta: datetime.timedelta | None = None
total_walltime: dict[str, Any] = field(default_factory=dict)
- output_size: Optional[int] = None
+ output_size: int | None = None
destination_user_concurrent_jobs: dict[str, int] = field(default_factory=dict)
destination_total_concurrent_jobs: dict[str, int] = field(default_factory=dict)
@@ -340,16 +339,16 @@ class JobConfiguration(ConfiguresHandlers):
"""Parse the job configuration XML."""
super().__init__(app)
self.runner_plugins: list[dict] = []
- self.dynamic_params: Optional[dict[str, Any]] = None
+ self.dynamic_params: dict[str, Any] | None = None
self.handler_runner_plugins: dict[str, str] = {}
- self.default_handler_id: Union[str, None] = None
- self.handler_ready_window_size: Union[int, None] = None
+ self.default_handler_id: str | None = None
+ self.handler_ready_window_size: int | None = None
self.destinations: dict[str, list[JobDestination]] = {}
- self.default_destination_id: Union[str, None] = None
+ self.default_destination_id: str | None = None
self.tools: dict[str, list[JobToolConfiguration]] = {}
self.tool_classes: dict[str, list[JobToolConfiguration]] = {}
self.resource_groups: dict[str, list[str]] = {}
- self.default_resource_group: Union[str, None] = None
+ self.default_resource_group: str | None = None
self.resource_parameters: dict[str, Any] = {}
self.limits = JobConfigurationLimits()
@@ -570,7 +569,7 @@ class JobConfiguration(ConfiguresHandlers):
for limit_dict in job_config_dict.get("limits", []):
limit_type = limit_dict.get("type")
if limit_type.startswith("environment_"):
- limit_type = f"destination_{limit_type[len('environment_'):]}"
+ limit_type = f"destination_{limit_type[len('environment_') :]}"
limit_value = limit_dict.get("value")
# concurrent_jobs renamed to destination_user_concurrent_jobs in job_conf.xml
@@ -767,9 +766,7 @@ class JobConfiguration(ConfiguresHandlers):
)
# Called upon instantiation of a Tool object
- def get_job_tool_configurations(
- self, ids: Union[str, list[str]], tool_classes: list[str]
- ) -> list[JobToolConfiguration]:
+ def get_job_tool_configurations(self, ids: str | list[str], tool_classes: list[str]) -> list[JobToolConfiguration]:
"""
Get all configured JobToolConfigurations for a tool ID, or, if given
a list of IDs, the JobToolConfigurations for the first id in ``ids``
@@ -813,7 +810,7 @@ class JobConfiguration(ConfiguresHandlers):
rval.append(self.default_job_tool_configuration)
return rval
- def get_destination(self, id_or_tag: Union[str, None]) -> JobDestination:
+ def get_destination(self, id_or_tag: str | None) -> JobDestination:
"""Given a destination ID or tag, return the JobDestination matching the provided ID or tag
:param id_or_tag: A destination ID or tag.
@@ -1014,7 +1011,7 @@ class MinimalJobWrapper(HasResourceParameters):
self.extra_filenames: list[str] = []
self.environment_variables: list[dict[str, str]] = []
self.interactivetools: list[dict[str, Any]] = []
- self.command_line: Union[str, None] = None
+ self.command_line: str | None = None
self.version_command_line = None
self._dependency_shell_commands = None
# Tool versioning variables
@@ -1027,7 +1024,7 @@ class MinimalJobWrapper(HasResourceParameters):
self._setup_working_directory(job=job)
# the path rewriter needs destination params, so it cannot be set up until after the destination has been
# resolved
- self._job_io: Optional[JobIO] = None
+ self._job_io: JobIO | None = None
self.tool_provided_job_metadata = None
self.params = None # unused
self.runner_command_line = None
@@ -1816,9 +1813,9 @@ class MinimalJobWrapper(HasResourceParameters):
def set_job_destination(
self,
job_destination: JobDestination,
- external_id: Union[str, None] = None,
+ external_id: str | None = None,
flush: bool = True,
- job: Union[Job, None] = None,
+ job: Job | None = None,
) -> None:
"""Subclasses should implement this to persist a destination, if necessary."""
@@ -1858,8 +1855,8 @@ class MinimalJobWrapper(HasResourceParameters):
def _set_object_store_ids_full(self, job: Job):
user = job.user
object_store_id = self.get_destination_configuration("object_store_id", None)
- split_object_stores: Optional[Callable[[str], ObjectStorePopulator]] = None
- object_store_id_overrides: Optional[dict[str, Optional[str]]] = None
+ split_object_stores: Callable[[str], ObjectStorePopulator] | None = None
+ object_store_id_overrides: dict[str, str | None] | None = None
if object_store_id is None:
object_store_id = job.preferred_object_store_id
@@ -2481,7 +2478,7 @@ class MinimalJobWrapper(HasResourceParameters):
"""Return complete command line, including possible version command."""
if self.remote_command_line:
return None
- return f'{self.version_command_line or ""}{self.command_line}'
+ return f"{self.version_command_line or ''}{self.command_line}"
def get_env_setup_clause(self):
if self.app.config.environment_setup_file is None:
@@ -2840,9 +2837,9 @@ class JobWrapper(MinimalJobWrapper):
def set_job_destination(
self,
job_destination: JobDestination,
- external_id: Union[str, None] = None,
+ external_id: str | None = None,
flush: bool = True,
- job: Union[Job, None] = None,
+ job: Job | None = None,
) -> None:
"""
Persist job destination params in the database for recovery.
diff --git a/lib/galaxy/jobs/command_factory.py b/lib/galaxy/jobs/command_factory.py
index b7c09a5cd8d..68cbad5e024 100644
--- a/lib/galaxy/jobs/command_factory.py
+++ b/lib/galaxy/jobs/command_factory.py
@@ -9,7 +9,6 @@ from os.path import (
abspath,
join,
)
-from typing import Optional
from galaxy import util
from galaxy.job_execution.output_collect import default_exit_code_file
@@ -39,7 +38,7 @@ SETUP_GALAXY_FOR_METADATA = """
def build_command(
runner: "BaseJobRunner",
job_wrapper: "MinimalJobWrapper",
- container: Optional[Container] = None,
+ container: Container | None = None,
modify_command_for_container: bool = True,
include_metadata: bool = False,
include_work_dir_outputs: bool = True,
@@ -166,7 +165,7 @@ def __externalize_commands(
commands_builder,
remote_command_params,
script_name="tool_script.sh",
- container: Optional[Container] = None,
+ container: Container | None = None,
):
local_container_script = join(job_wrapper.working_directory, script_name)
tool_commands = commands_builder.build()
diff --git a/lib/galaxy/jobs/dynamic_tool_destination.py b/lib/galaxy/jobs/dynamic_tool_destination.py
index 9c694e784b7..81fe2c05082 100755
--- a/lib/galaxy/jobs/dynamic_tool_destination.py
+++ b/lib/galaxy/jobs/dynamic_tool_destination.py
@@ -9,9 +9,7 @@ import re
import sys
from functools import reduce
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
)
import numpy as np
@@ -78,7 +76,7 @@ class ScannerError(Exception):
pass
-def get_keys_from_dict(dl: Union[dict, list], keys_list: list) -> None:
+def get_keys_from_dict(dl: dict | list, keys_list: list) -> None:
"""
This function builds a list using the keys from nest dictionaries
"""
@@ -1267,10 +1265,10 @@ def map_tool_to_destination(
job: "Job",
app: "MinimalManagerApp",
tool: "Tool",
- user_email: Optional[str],
+ user_email: str | None,
test: bool = False,
- path: Optional[str] = None,
- job_conf_path: Optional[str] = None,
+ path: str | None = None,
+ job_conf_path: str | None = None,
):
"""
Dynamically allocate resources
diff --git a/lib/galaxy/jobs/handler.py b/lib/galaxy/jobs/handler.py
index 8f332c09663..958a633d710 100644
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -15,7 +15,6 @@ from typing import (
Any,
Optional,
TYPE_CHECKING,
- Union,
)
from sqlalchemy.exc import OperationalError
@@ -114,13 +113,13 @@ class JobHandler(JobHandlerI):
class ItemGrabber:
- grab_model: Union[type[model.Job], type[model.WorkflowInvocation]]
+ grab_model: type[model.Job] | type[model.WorkflowInvocation]
def __init__(
self,
app: MinimalManagerApp,
handler_assignment_method=None,
- max_grab: Union[int, None] = None,
+ max_grab: int | None = None,
self_handler_tags=None,
handler_tags=None,
) -> None:
@@ -251,7 +250,7 @@ class BaseJobHandlerQueue(JobQueueI, Monitors):
# Keep track of the pid that started the job manager, only it has valid threads
self.parent_pid = os.getpid()
# This queue is not used if track_jobs_in_database is True.
- self.queue: Queue[tuple[int, Optional[str]]] = Queue()
+ self.queue: Queue[tuple[int, str | None]] = Queue()
class JobHandlerQueue(BaseJobHandlerQueue):
@@ -1109,7 +1108,7 @@ class JobHandlerStopQueue(BaseJobHandlerQueue):
# Sleep
self._monitor_sleep(1)
- def __delete(self, job: model.Job, error_msg: Optional[str]):
+ def __delete(self, job: model.Job, error_msg: str | None):
final_state = job.states.DELETED
if error_msg is not None:
final_state = job.states.ERROR
@@ -1128,7 +1127,7 @@ class JobHandlerStopQueue(BaseJobHandlerQueue):
Called repeatedly by `monitor` to stop jobs.
"""
# Pull all new jobs from the queue at once
- jobs_to_check: list[tuple[model.Job, Optional[str]]] = []
+ jobs_to_check: list[tuple[model.Job, str | None]] = []
with self.sa_session.begin():
self._add_newly_deleted_jobs(jobs_to_check)
try:
@@ -1137,7 +1136,7 @@ class JobHandlerStopQueue(BaseJobHandlerQueue):
return
self._check_jobs(jobs_to_check)
- def put(self, job_id: int, error_msg: Optional[str] = None):
+ def put(self, job_id: int, error_msg: str | None = None):
if not self.track_jobs_in_database:
self.queue.put((job_id, error_msg))
@@ -1154,7 +1153,7 @@ class JobHandlerStopQueue(BaseJobHandlerQueue):
self.shutdown_monitor()
log.info("job handler stop queue stopped")
- def _add_newly_deleted_jobs(self, jobs_to_check: list[tuple[model.Job, Optional[str]]]):
+ def _add_newly_deleted_jobs(self, jobs_to_check: list[tuple[model.Job, str | None]]):
if self.track_jobs_in_database:
newly_deleted_jobs = self._get_new_jobs()
for job in newly_deleted_jobs:
@@ -1170,7 +1169,7 @@ class JobHandlerStopQueue(BaseJobHandlerQueue):
)
return self.sa_session.scalars(stmt).all()
- def _pull_from_queue(self, jobs_to_check: list[tuple[model.Job, Optional[str]]]):
+ def _pull_from_queue(self, jobs_to_check: list[tuple[model.Job, str | None]]):
# Pull jobs from the queue (in the case of Administrative stopped jobs)
try:
while 1:
@@ -1184,7 +1183,7 @@ class JobHandlerStopQueue(BaseJobHandlerQueue):
except Empty:
pass
- def _check_jobs(self, jobs_to_check: list[tuple[model.Job, Optional[str]]]):
+ def _check_jobs(self, jobs_to_check: list[tuple[model.Job, str | None]]):
for job, error_msg in jobs_to_check:
if (
job.state
diff --git a/lib/galaxy/jobs/job_destination.py b/lib/galaxy/jobs/job_destination.py
index 1a9fc0701df..1be5c92ca48 100644
--- a/lib/galaxy/jobs/job_destination.py
+++ b/lib/galaxy/jobs/job_destination.py
@@ -20,13 +20,13 @@ class JobDestination:
Provides details about where a job runs
"""
- id: Union[str, None] = None
- url: Union[str, None] = None
- tags: Union[list[str], None] = None
- runner: Union[str, None] = None
+ id: str | None = None
+ url: str | None = None
+ tags: list[str] | None = None
+ runner: str | None = None
legacy: bool = False
converted: bool = False
- shell: Union[str, None] = None
+ shell: str | None = None
env: list[dict[str, Any]] = field(default_factory=list)
resubmit: list["ResubmitConfigDict"] = field(default_factory=list)
params: dict[str, Any] = field(default_factory=dict)
diff --git a/lib/galaxy/jobs/mapper.py b/lib/galaxy/jobs/mapper.py
index ce6ccea0efb..c3a26d6cc6f 100644
--- a/lib/galaxy/jobs/mapper.py
+++ b/lib/galaxy/jobs/mapper.py
@@ -5,7 +5,6 @@ from inspect import getfullargspec
from types import ModuleType
from typing import (
TYPE_CHECKING,
- Union,
)
import galaxy.jobs.rules
@@ -161,7 +160,7 @@ class JobRunnerMapper:
dest.id = DYNAMIC_DESTINATION_ID
return dest
- def __find_function_by_tool_id(self, rule_modules: list[ModuleType]) -> Union[Callable, None]:
+ def __find_function_by_tool_id(self, rule_modules: list[ModuleType]) -> Callable | None:
assert self.job_wrapper.tool is not None
# default look for function with name matching an id of tool, unless one specified
for tool_id in self.job_wrapper.tool.all_ids:
@@ -190,7 +189,7 @@ class JobRunnerMapper:
raise JobMappingConfigurationException(message)
return expand_function
- def __get_rule_modules_or_defaults(self, rules_module_name: Union[str, None]) -> list[ModuleType]:
+ def __get_rule_modules_or_defaults(self, rules_module_name: str | None) -> list[ModuleType]:
"""
Returns the rules under the given rules_module_name or default
to returning the rules of the top-level rules module for the plugin
@@ -203,7 +202,7 @@ class JobRunnerMapper:
def __last_matching_function_in_modules(
self, rule_modules: list[ModuleType], function_name: str
- ) -> Union[Callable, None]:
+ ) -> Callable | None:
# self.rule_modules is sorted in reverse order, so find first
# with function
for rule_module in rule_modules:
@@ -253,7 +252,7 @@ class JobRunnerMapper:
return job_destination
def __determine_job_destination(
- self, params: Union[dict, None], raw_job_destination: Union[JobDestination, None] = None
+ self, params: dict | None, raw_job_destination: JobDestination | None = None
) -> JobDestination:
if raw_job_destination is None:
if self.job_wrapper.tool is None:
@@ -272,7 +271,7 @@ class JobRunnerMapper:
return job_destination
def __cache_job_destination(
- self, params: Union[dict, None], raw_job_destination: Union[JobDestination, None] = None
+ self, params: dict | None, raw_job_destination: JobDestination | None = None
) -> JobDestination:
try:
self.cached_job_destination = self.__determine_job_destination(
@@ -287,7 +286,7 @@ class JobRunnerMapper:
raise JobMappingException(ERROR_MESSAGE_RULE_EXCEPTION)
return self.cached_job_destination
- def get_job_destination(self, params: Union[dict, None]) -> JobDestination:
+ def get_job_destination(self, params: dict | None) -> JobDestination:
"""
cached_job_destination is a public property that is sometimes
externally set to short-circuit the mapper, such as during resubmits.
@@ -297,7 +296,7 @@ class JobRunnerMapper:
return self.__cache_job_destination(params)
return self.cached_job_destination
- def cache_job_destination(self, raw_job_destination: Union[JobDestination, None]) -> JobDestination:
+ def cache_job_destination(self, raw_job_destination: JobDestination | None) -> JobDestination:
"""
Force update of cached_job_destination to mapper determined job
destination, overwriting any externally set cached_job_destination
diff --git a/lib/galaxy/jobs/runners/__init__.py b/lib/galaxy/jobs/runners/__init__.py
index 5b98b1d6172..5ba3354754c 100644
--- a/lib/galaxy/jobs/runners/__init__.py
+++ b/lib/galaxy/jobs/runners/__init__.py
@@ -18,7 +18,6 @@ from queue import (
from typing import (
Any,
Generic,
- Optional,
TYPE_CHECKING,
TypeVar,
Union,
@@ -358,8 +357,8 @@ class BaseJobRunner:
def get_work_dir_outputs(
self,
job_wrapper: "MinimalJobWrapper",
- job_working_directory: Optional[str] = None,
- tool_working_directory: Optional[str] = None,
+ job_working_directory: str | None = None,
+ tool_working_directory: str | None = None,
):
"""
Returns list of pairs (source_file, destination) describing path
@@ -543,10 +542,10 @@ class BaseJobRunner:
def _find_container(
self,
job_wrapper: "MinimalJobWrapper",
- compute_working_directory: Optional[str] = None,
- compute_tool_directory: Optional[str] = None,
- compute_job_directory: Optional[str] = None,
- compute_tmp_directory: Optional[str] = None,
+ compute_working_directory: str | None = None,
+ compute_tool_directory: str | None = None,
+ compute_job_directory: str | None = None,
+ compute_tmp_directory: str | None = None,
):
job_directory_type = "galaxy" if compute_working_directory is None else "pulsar"
if not compute_working_directory:
@@ -603,7 +602,7 @@ class BaseJobRunner:
job_state: "JobState",
exception: bool = False,
message: str = "Job failed",
- full_status: Union[dict[str, Any], None] = None,
+ full_status: dict[str, Any] | None = None,
) -> None:
job = job_state.job_wrapper.get_job()
if job_state.stop_job and job.state != model.Job.states.NEW:
@@ -623,7 +622,7 @@ class BaseJobRunner:
fail_message, tool_stdout=tool_stdout, tool_stderr=tool_stderr, exception=exception
)
- def mark_as_resubmitted(self, job_state: "JobState", info: Optional[str] = None):
+ def mark_as_resubmitted(self, job_state: "JobState", info: str | None = None):
job_state.job_wrapper.mark_as_resubmitted(info=info)
if not self.app.config.track_jobs_in_database:
assert self.app.job_manager.job_handler.dispatcher
@@ -787,7 +786,7 @@ class AsynchronousJobState(JobState):
job_destination: JobDestination,
*,
files_dir=None,
- job_id: Union[str, None] = None,
+ job_id: str | None = None,
job_file=None,
output_file=None,
error_file=None,
@@ -798,7 +797,7 @@ class AsynchronousJobState(JobState):
self.old_state = None
self._running = False
self.check_count = 0
- self.start_time: Union[datetime.datetime, None] = None
+ self.start_time: datetime.datetime | None = None
# job_id is the DRM's job id, not the Galaxy job id
self.job_id = job_id
@@ -946,10 +945,10 @@ class AsynchronousJobRunner(BaseJobRunner, Monitors, Generic[T]):
self.watched = new_watched
# Subclasses should implement this unless they override check_watched_items all together.
- def check_watched_item(self, job_state: T) -> Union[T, None]:
+ def check_watched_item(self, job_state: T) -> T | None:
raise NotImplementedError()
- def _collect_job_output(self, job_id: int, external_job_id: Optional[str], job_state: JobState):
+ def _collect_job_output(self, job_id: int, external_job_id: str | None, job_state: JobState):
# wait for the files to appear
which_try = 0
collect_output_success = True
diff --git a/lib/galaxy/jobs/runners/aws.py b/lib/galaxy/jobs/runners/aws.py
index 998b4c1731d..3d40c8cba70 100644
--- a/lib/galaxy/jobs/runners/aws.py
+++ b/lib/galaxy/jobs/runners/aws.py
@@ -9,7 +9,6 @@ import re
from typing import (
Any,
TYPE_CHECKING,
- Union,
)
from galaxy import model
@@ -419,7 +418,7 @@ class AWSBatchJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
ajs.running = False
self.monitor_queue.put(ajs)
- def fail_job(self, job_state: JobState, exception: bool = False, message: str = "Job failed", full_status: Union[dict[str, Any], None] = None) -> None:
+ def fail_job(self, job_state: JobState, exception: bool = False, message: str = "Job failed", full_status: dict[str, Any] | None = None) -> None:
job = job_state.job_wrapper.get_job()
if job_state.stop_job and job.state != model.Job.states.NEW:
self.stop_job(job_state.job_wrapper)
diff --git a/lib/galaxy/jobs/runners/chronos.py b/lib/galaxy/jobs/runners/chronos.py
index d8dcc31822e..4ee260cfb6f 100644
--- a/lib/galaxy/jobs/runners/chronos.py
+++ b/lib/galaxy/jobs/runners/chronos.py
@@ -3,7 +3,6 @@ import logging
import os
from typing import (
TYPE_CHECKING,
- Union,
)
from galaxy import model
@@ -205,7 +204,7 @@ class ChronosJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
self.monitor_queue.put(ajs)
@handle_exception_call
- def check_watched_item(self, job_state: AsynchronousJobState) -> Union[AsynchronousJobState, None]:
+ def check_watched_item(self, job_state: AsynchronousJobState) -> AsynchronousJobState | None:
job_name = job_state.job_id
# TODO: how can stopped GxIT jobs be handled here?
if job := self._retrieve_job(job_name):
diff --git a/lib/galaxy/jobs/runners/condor.py b/lib/galaxy/jobs/runners/condor.py
index b18015ca1a6..ffeda7649cf 100644
--- a/lib/galaxy/jobs/runners/condor.py
+++ b/lib/galaxy/jobs/runners/condor.py
@@ -16,7 +16,6 @@ import os
import subprocess
from typing import (
TYPE_CHECKING,
- Union,
)
from galaxy import model
@@ -50,7 +49,7 @@ class CondorJobState(AsynchronousJobState):
user_log: str,
*,
files_dir=None,
- job_id: Union[str, None] = None,
+ job_id: str | None = None,
job_file=None,
output_file=None,
error_file=None,
diff --git a/lib/galaxy/jobs/runners/drmaa.py b/lib/galaxy/jobs/runners/drmaa.py
index e6242cca853..c3a3507c801 100644
--- a/lib/galaxy/jobs/runners/drmaa.py
+++ b/lib/galaxy/jobs/runners/drmaa.py
@@ -252,7 +252,7 @@ class DRMAAJobRunner(AsynchronousJobRunner[DRMAAJobState]):
# Add to our 'queue' of jobs to monitor
self.monitor_queue.put(ajs)
- def _complete_terminal_job(self, ajs: DRMAAJobState, drmaa_state: str, **kwargs) -> Union[bool, None]:
+ def _complete_terminal_job(self, ajs: DRMAAJobState, drmaa_state: str, **kwargs) -> bool | None:
"""
Handle a job upon its termination in the DRM. This method is meant to
be overridden by subclasses to improve post-mortem and reporting of
@@ -278,7 +278,7 @@ class DRMAAJobRunner(AsynchronousJobRunner[DRMAAJobState]):
self.work_queue.put((self.finish_job, ajs))
return None
- def check_watched_item_drmaa(self, ajs: DRMAAJobState, new_watched: list[DRMAAJobState]) -> Union[str, None]:
+ def check_watched_item_drmaa(self, ajs: DRMAAJobState, new_watched: list[DRMAAJobState]) -> str | None:
"""
look at a single watched job, determine its state, and deal with errors
that could happen in this process. to be called from check_watched_items()
diff --git a/lib/galaxy/jobs/runners/gcp_batch.py b/lib/galaxy/jobs/runners/gcp_batch.py
index 694f0d3fbd4..75bc9d13f55 100644
--- a/lib/galaxy/jobs/runners/gcp_batch.py
+++ b/lib/galaxy/jobs/runners/gcp_batch.py
@@ -119,8 +119,7 @@ class GoogleCloudBatchJobRunner(AsynchronousJobRunner):
def _init_batch_client(self):
"""Initialize the Google Cloud Batch client."""
# Set up authentication
- service_account_file = self.runner_params.get("service_account_file")
- if service_account_file:
+ if service_account_file := self.runner_params.get("service_account_file"):
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = service_account_file
try:
@@ -408,8 +407,7 @@ class GoogleCloudBatchJobRunner(AsynchronousJobRunner):
allocation_policy.instances = [instance_template]
# Configure service account for job execution
- service_account_email = params.get("service_account_email")
- if service_account_email:
+ if service_account_email := params.get("service_account_email"):
service_account = batch_v1.ServiceAccount()
service_account.email = service_account_email
allocation_policy.service_account = service_account
@@ -558,8 +556,7 @@ class GoogleCloudBatchJobRunner(AsynchronousJobRunner):
nfs_mount_path = DEFAULT_NFS_MOUNT_PATH
# Build Docker volume arguments from docker_extra_volumes parameter
- docker_volumes_param = params.get("docker_extra_volumes")
- if docker_volumes_param:
+ if docker_volumes_param := params.get("docker_extra_volumes"):
docker_volume_args = parse_docker_volumes_param(docker_volumes_param)
else:
# Default to CVMFS mount if no extra volumes specified
@@ -789,8 +786,7 @@ class GoogleCloudBatchJobRunner(AsynchronousJobRunner):
job = job_wrapper.get_job()
log.debug("Starting stop_job for job %s", job.id)
- batch_job_name = job.get_job_runner_external_id()
- if batch_job_name:
+ if batch_job_name := job.get_job_runner_external_id():
if not self.runner_params.get("delete_completed_jobs", True):
try:
job_path = f"projects/{self.runner_params['project_id']}/locations/{self.runner_params['region']}/jobs/{batch_job_name}"
diff --git a/lib/galaxy/jobs/runners/godocker.py b/lib/galaxy/jobs/runners/godocker.py
index 316933b6fef..5e8fe1110d7 100644
--- a/lib/galaxy/jobs/runners/godocker.py
+++ b/lib/galaxy/jobs/runners/godocker.py
@@ -4,7 +4,6 @@ import time
from datetime import datetime
from typing import (
TYPE_CHECKING,
- Union,
)
from galaxy import model
@@ -176,7 +175,7 @@ class GodockerJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
)
self.monitor_queue.put(ajs)
- def check_watched_item(self, job_state: AsynchronousJobState) -> Union[AsynchronousJobState, None]:
+ def check_watched_item(self, job_state: AsynchronousJobState) -> AsynchronousJobState | None:
"""Get the job current status from GoDocker
using job_id and update the status in galaxy.
If the job execution is successful, call
diff --git a/lib/galaxy/jobs/runners/htcondor.py b/lib/galaxy/jobs/runners/htcondor.py
index 7115961f1dc..0eb7aa6406f 100644
--- a/lib/galaxy/jobs/runners/htcondor.py
+++ b/lib/galaxy/jobs/runners/htcondor.py
@@ -364,8 +364,7 @@ class _HTCondorSubprocessClient(_HTCondorClient):
def _helper_failure_message_locked(self, message: str) -> str:
# Stderr is consumed by the drain thread and buffered in _stderr_lines.
- recent = "\n".join(list(self._stderr_lines)[-10:]).strip()
- if recent:
+ if recent := "\n".join(list(self._stderr_lines)[-10:]).strip():
return f"{message}: {recent}"
return message
@@ -724,8 +723,7 @@ class HTCondorJobRunner(AsynchronousJobRunner[HTCondorJobState]):
# generic held_count escalation logic.
if hold_reason_code in _HOLD_CODE_MEMORY:
log.info(
- f"({galaxy_id_tag}/{job_id}) job held for memory limit "
- f"(HoldReasonCode={hold_reason_code})"
+ f"({galaxy_id_tag}/{job_id}) job held for memory limit (HoldReasonCode={hold_reason_code})"
)
cjs.fail_message = _MEMORY_LIMIT_HOLD_MSG
cjs.runner_state = runner_states.MEMORY_LIMIT_REACHED
diff --git a/lib/galaxy/jobs/runners/kubernetes.py b/lib/galaxy/jobs/runners/kubernetes.py
index c6f9914f5ce..e72f906b372 100644
--- a/lib/galaxy/jobs/runners/kubernetes.py
+++ b/lib/galaxy/jobs/runners/kubernetes.py
@@ -12,7 +12,6 @@ from datetime import datetime
from typing import (
Any,
TYPE_CHECKING,
- Union,
)
import yaml
@@ -695,7 +694,7 @@ class KubernetesJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
def __get_k8s_job_name(self, prefix, job_wrapper):
return f"{prefix}-{self.__force_label_conformity(job_wrapper.get_id_tag())}"
- def check_watched_item(self, job_state: AsynchronousJobState) -> Union[AsynchronousJobState, None]:
+ def check_watched_item(self, job_state: AsynchronousJobState) -> AsynchronousJobState | None:
"""Checks the state of a job already submitted on k8s. Job state is an AsynchronousJobState"""
jobs = find_job_object_by_name(self._pykube_api, job_state.job_id, self.runner_params["k8s_namespace"])
@@ -1090,7 +1089,7 @@ class KubernetesJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
job_state: "JobState",
exception: bool = False,
message: str = "Job failed",
- full_status: Union[dict[str, Any], None] = None,
+ full_status: dict[str, Any] | None = None,
) -> None:
log.debug("PP Getting into fail_job in k8s runner")
gxy_job = job_state.job_wrapper.get_job()
diff --git a/lib/galaxy/jobs/runners/pulsar.py b/lib/galaxy/jobs/runners/pulsar.py
index b456427d141..c914ec271cf 100644
--- a/lib/galaxy/jobs/runners/pulsar.py
+++ b/lib/galaxy/jobs/runners/pulsar.py
@@ -14,7 +14,6 @@ from typing import (
Any,
Optional,
TYPE_CHECKING,
- Union,
)
import pulsar.core
@@ -311,7 +310,7 @@ class PulsarJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
"""Convert a legacy URL to a job destination."""
return JobDestination(runner="pulsar", params=url_to_destination_params(url))
- def check_watched_item(self, job_state: AsynchronousJobState) -> Union[AsynchronousJobState, None]:
+ def check_watched_item(self, job_state: AsynchronousJobState) -> AsynchronousJobState | None:
if self.use_mq:
# Might still need to check pod IPs.
job_wrapper = job_state.job_wrapper
@@ -342,7 +341,7 @@ class PulsarJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
else:
return self.check_watched_item_state(job_state)
- def check_watched_item_state(self, job_state: AsynchronousJobState) -> Union[AsynchronousJobState, None]:
+ def check_watched_item_state(self, job_state: AsynchronousJobState) -> AsynchronousJobState | None:
try:
client = self.get_client_from_state(job_state)
status = client.get_status()
@@ -359,9 +358,9 @@ class PulsarJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
def _update_job_state_for_status(
self,
job_state: AsynchronousJobState,
- pulsar_status: Union[str, None],
- full_status: Union[dict[str, Any], None] = None,
- ) -> Union[AsynchronousJobState, None]:
+ pulsar_status: str | None,
+ full_status: dict[str, Any] | None = None,
+ ) -> AsynchronousJobState | None:
log.debug("(%s) Received status update: %s", job_state.job_id, pulsar_status)
if pulsar_status in ["complete", "cancelled"]:
self.mark_as_finished(job_state)
@@ -516,7 +515,7 @@ class PulsarJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
command_line = None
client = None
remote_job_config = None
- compute_environment: Optional[PulsarComputeEnvironment] = None
+ compute_environment: PulsarComputeEnvironment | None = None
remote_container = None
fail_or_resubmit = False
@@ -674,9 +673,7 @@ class PulsarJobRunner(AsynchronousJobRunner[AsynchronousJobState]):
job_id = job_state.job_wrapper.job_id # we want the Galaxy ID here, job_state.job_id is the external one.
return self.get_client(job_destination_params, job_id)
- def get_client(
- self, job_destination_params: dict[str, Any], job_id, env: Union[list, None] = None
- ) -> "BaseJobClient":
+ def get_client(self, job_destination_params: dict[str, Any], job_id, env: list | None = None) -> "BaseJobClient":
# Cannot use url_for outside of web thread.
# files_endpoint = url_for( controller="job_files", job_id=encoded_job_id )
if env is None:
diff --git a/lib/galaxy/jobs/runners/slurm.py b/lib/galaxy/jobs/runners/slurm.py
index db34b4f5f3b..79e02211c07 100644
--- a/lib/galaxy/jobs/runners/slurm.py
+++ b/lib/galaxy/jobs/runners/slurm.py
@@ -6,7 +6,6 @@ import os
import time
from typing import (
TYPE_CHECKING,
- Union,
)
from galaxy import model
@@ -47,7 +46,7 @@ class SlurmJobRunner(DRMAAJobRunner):
runner_name = "SlurmRunner"
restrict_job_name_length = False
- def _complete_terminal_job(self, ajs: "DRMAAJobState", drmaa_state: str, **kwargs) -> Union[bool, None]:
+ def _complete_terminal_job(self, ajs: "DRMAAJobState", drmaa_state: str, **kwargs) -> bool | None:
def _get_slurm_state_with_sacct(job_id, cluster):
cmd = ["sacct", "-n", "-o", "state%-32"]
if cluster:
diff --git a/lib/galaxy/jobs/runners/univa.py b/lib/galaxy/jobs/runners/univa.py
index 54b7c4556fc..d4b6ee21f5b 100644
--- a/lib/galaxy/jobs/runners/univa.py
+++ b/lib/galaxy/jobs/runners/univa.py
@@ -36,7 +36,6 @@ import time
from math import inf
from typing import (
TYPE_CHECKING,
- Union,
)
from galaxy.jobs.runners.drmaa import DRMAAJobRunner
@@ -79,7 +78,7 @@ class UnivaJobRunner(DRMAAJobRunner):
return self.drmaa.JobState.DONE
return state
- def _complete_terminal_job(self, ajs: "DRMAAJobState", drmaa_state: str, **kwargs) -> Union[bool, None]:
+ def _complete_terminal_job(self, ajs: "DRMAAJobState", drmaa_state: str, **kwargs) -> bool | None:
extinfo: dict = {}
assert ajs.job_id is not None
# get state with job_info/qstat + wait/qacct
@@ -454,7 +453,7 @@ class UnivaJobRunner(DRMAAJobRunner):
# log.debug("UnivaJobRunner._get_drmaa_state_wait ({jobid}) -> {state}".format(jobid=job_id, state=self.drmaa_job_state_strings[state]))
return state
- def _get_drmaa_state(self, job_id: str, ds, waitqacct: bool, extinfo: Union[dict, None] = None) -> str:
+ def _get_drmaa_state(self, job_id: str, ds, waitqacct: bool, extinfo: dict | None = None) -> str:
"""
get the state using drmaa.job_info/qstat and drmaa.wait/qacct using the above functions
qacct/wait is only called if waitqacct is True.
diff --git a/lib/galaxy/jobs/runners/util/job_script/__init__.py b/lib/galaxy/jobs/runners/util/job_script/__init__.py
index 9ae3f49cd0c..e20053a49f3 100644
--- a/lib/galaxy/jobs/runners/util/job_script/__init__.py
+++ b/lib/galaxy/jobs/runners/util/job_script/__init__.py
@@ -6,7 +6,6 @@ from dataclasses import dataclass
from string import Template
from typing import (
Any,
- Optional,
)
from typing_extensions import Protocol
@@ -130,8 +129,8 @@ def job_script(template=DEFAULT_JOB_FILE_TEMPLATE, **kwds):
class DescribesScriptIntegrityChecks(Protocol):
check_job_script_integrity: bool
- check_job_script_integrity_count: Optional[int]
- check_job_script_integrity_sleep: Optional[float]
+ check_job_script_integrity_count: int | None
+ check_job_script_integrity_sleep: float | None
@dataclass
@@ -139,8 +138,8 @@ class ScriptIntegrityChecks:
"""Minimal class implementing the DescribesScriptIntegrityChecks protocol"""
check_job_script_integrity: bool
- check_job_script_integrity_count: Optional[int] = None
- check_job_script_integrity_sleep: Optional[float] = None
+ check_job_script_integrity_count: int | None = None
+ check_job_script_integrity_sleep: float | None = None
def write_script(path: str, contents, job_io: DescribesScriptIntegrityChecks, mode: int = RWXR_XR_X) -> None:
diff --git a/lib/galaxy/main_config/__init__.py b/lib/galaxy/main_config/__init__.py
index 23ba644da47..d29192efdf7 100644
--- a/lib/galaxy/main_config/__init__.py
+++ b/lib/galaxy/main_config/__init__.py
@@ -6,7 +6,6 @@ This is for use by web framework code and scripts (e.g. scripts/galaxy_main.py).
import os
from typing import (
NamedTuple,
- Optional,
)
from galaxy.util.properties import find_config_file
@@ -24,17 +23,17 @@ def default_relative_config_paths_for(app_name: str) -> list[str]:
return paths
-def absolute_config_path(path, galaxy_root: Optional[str]) -> Optional[str]:
+def absolute_config_path(path, galaxy_root: str | None) -> str | None:
if path and not os.path.isabs(path) and galaxy_root:
path = os.path.join(galaxy_root, path)
return path
-def config_is_ini(config_file: Optional[str]) -> bool:
+def config_is_ini(config_file: str | None) -> bool:
return bool(config_file and (config_file.endswith(".ini") or config_file.endswith(".ini.sample")))
-def find_config(supplied_config: Optional[str], galaxy_root: Optional[str], app_name: str = "galaxy") -> Optional[str]:
+def find_config(supplied_config: str | None, galaxy_root: str | None, app_name: str = "galaxy") -> str | None:
if supplied_config:
return supplied_config
@@ -56,7 +55,7 @@ class WebappSetupProps(NamedTuple):
app_name: str
default_section_name: str
env_config_file: str
- env_config_section: Optional[str] = None
+ env_config_section: str | None = None
check_galaxy_root: bool = False
@@ -85,7 +84,7 @@ class WebappConfigResolver:
return WebappConfig(global_conf=global_conf, load_app_kwds=self.app_kwds)
- def _resolve_config_file_path(self) -> Optional[str]:
+ def _resolve_config_file_path(self) -> str | None:
config_file = self.app_kwds.get("config_file")
if not config_file and os.environ.get(self.props.env_config_file):
config_file = os.path.abspath(os.environ[self.props.env_config_file])
diff --git a/lib/galaxy/managers/_config_templates.py b/lib/galaxy/managers/_config_templates.py
index f3f0cef132d..a4206107688 100644
--- a/lib/galaxy/managers/_config_templates.py
+++ b/lib/galaxy/managers/_config_templates.py
@@ -3,9 +3,7 @@ import os
from typing import (
Any,
cast,
- Optional,
TypeVar,
- Union,
)
from pydantic import (
@@ -64,20 +62,20 @@ SuppliedSecrets = dict[str, str]
class CreateInstancePayload(BaseModel):
name: str
- description: Optional[str] = None
+ description: str | None = None
template_id: str
template_version: int
variables: SuppliedVariables
secrets: SuppliedSecrets
- uuid: Optional[UUID4] = None
+ uuid: UUID4 | None = None
class UpdateInstancePayload(BaseModel):
- name: Optional[str] = None
- description: Optional[str] = None
- variables: Optional[SuppliedVariables] = None
- hidden: Optional[bool] = None
- active: Optional[bool] = None
+ name: str | None = None
+ description: str | None = None
+ variables: SuppliedVariables | None = None
+ hidden: bool | None = None
+ active: bool | None = None
class UpdateInstanceSecretPayload(BaseModel):
@@ -92,7 +90,7 @@ class UpgradeInstancePayload(BaseModel):
class TestUpdateInstancePayload(BaseModel):
- variables: Optional[SuppliedVariables] = None
+ variables: SuppliedVariables | None = None
class TestUpgradeInstancePayload(BaseModel):
@@ -128,13 +126,13 @@ class CreateTestTarget:
self.instance_class = instance_class
-ModifyInstancePayload = Union[UpdateInstanceSecretPayload, UpgradeInstancePayload, UpdateInstancePayload]
-TestModifyInstancePayload = Union[TestUpgradeInstancePayload, TestUpdateInstancePayload]
-CanTestPluginStatus = Union[HasConfigTemplate, CreateTestTarget, UpgradeTestTarget, UpdateTestTarget]
+ModifyInstancePayload = UpdateInstanceSecretPayload | UpgradeInstancePayload | UpdateInstancePayload
+TestModifyInstancePayload = TestUpgradeInstancePayload | TestUpdateInstancePayload
+CanTestPluginStatus = HasConfigTemplate | CreateTestTarget | UpgradeTestTarget | UpdateTestTarget
def recover_secrets(
- user_object_store: HasConfigSecrets, vault: Union[UserVaultWrapper, Vault], app_config: UsesTemplatesAppConfig
+ user_object_store: HasConfigSecrets, vault: UserVaultWrapper | Vault, app_config: UsesTemplatesAppConfig
) -> SecretsDict:
if isinstance(vault, UserVaultWrapper):
user_vault = vault
@@ -160,7 +158,7 @@ class TemplateParameters(TypedDict):
variables: SuppliedVariables
environment: EnvironmentDict
user_details: dict[str, Any]
- implicit: Optional[ImplicitConfigurationParameters]
+ implicit: ImplicitConfigurationParameters | None
class TemplateServerConfiguration:
@@ -171,14 +169,14 @@ class TemplateServerConfiguration:
information (provider URLs and provider specific configuration for the oauth2 flow).
"""
- oauth2_client_pair: Optional[OAuth2ClientPair]
- oauth2_configuration: Optional[OAuth2Configuration]
+ oauth2_client_pair: OAuth2ClientPair | None
+ oauth2_configuration: OAuth2Configuration | None
def __init__(
self,
- oauth2_client_pair: Optional[OAuth2ClientPair] = None,
- oauth2_configuration: Optional[OAuth2Configuration] = None,
- oauth2_scope: Optional[str] = None,
+ oauth2_client_pair: OAuth2ClientPair | None = None,
+ oauth2_configuration: OAuth2Configuration | None = None,
+ oauth2_scope: str | None = None,
):
self.oauth2_client_pair = oauth2_client_pair
self.oauth2_configuration = oauth2_configuration
@@ -267,7 +265,7 @@ def prepare_environment(
def prepare_environment_from_root(
- root: Optional[list[TemplateEnvironmentEntry]], vault: Vault, app_config: UsesTemplatesAppConfig
+ root: list[TemplateEnvironmentEntry] | None, vault: Vault, app_config: UsesTemplatesAppConfig
) -> EnvironmentDict:
environment: EnvironmentDict = {}
for environment_entry in root or []:
@@ -429,7 +427,7 @@ T = TypeVar("T", bound=Template, covariant=True)
def sort_templates(config, catalog: list[T], instance: HasConfigTemplate) -> list[T]:
- configured_template: Optional[T] = None
+ configured_template: T | None = None
try:
configured_template = find_template_by(
catalog, instance.template_id, instance.template_version, "config template"
@@ -452,7 +450,7 @@ def implicit_parameters_for_testing(
template_server_configuration: TemplateServerConfiguration,
target: CanTestPluginStatus,
app_config: UsesTemplatesAppConfig,
-) -> Optional[ImplicitConfigurationParameters]:
+) -> ImplicitConfigurationParameters | None:
implicit: ImplicitConfigurationParameters = {}
if template_server_configuration.oauth2_configuration:
refresh_token_key = None
@@ -516,8 +514,8 @@ def _inject_oauth2_access_token(
def oauth2_refresh_token_status(
- template_server_configuration: TemplateServerConfiguration, exception: Optional[Exception]
-) -> Optional[PluginAspectStatus]:
+ template_server_configuration: TemplateServerConfiguration, exception: Exception | None
+) -> PluginAspectStatus | None:
if not template_server_configuration.uses_oauth2:
# no oauth enabled, don't report a status associated with
return None
diff --git a/lib/galaxy/managers/agents.py b/lib/galaxy/managers/agents.py
index 0b51493abec..29740ebdca8 100644
--- a/lib/galaxy/managers/agents.py
+++ b/lib/galaxy/managers/agents.py
@@ -3,7 +3,6 @@
import logging
from typing import (
Any,
- Optional,
)
from galaxy.agents import GalaxyAgentDependencies
@@ -50,7 +49,7 @@ class AgentService:
query: str,
trans: ProvidesUserContext,
user: User,
- context: Optional[dict[str, Any]] = None,
+ context: dict[str, Any] | None = None,
) -> AgentResponse:
"""Execute a specific agent and return response."""
deps = self.create_dependencies(trans, user)
@@ -99,7 +98,7 @@ class AgentService:
query: str,
trans: ProvidesUserContext,
user: User,
- context: Optional[dict[str, Any]] = None,
+ context: dict[str, Any] | None = None,
agent_type: str = "auto",
) -> AgentResponse:
"""
diff --git a/lib/galaxy/managers/annotatable.py b/lib/galaxy/managers/annotatable.py
index 487855dba83..2a6bc325521 100644
--- a/lib/galaxy/managers/annotatable.py
+++ b/lib/galaxy/managers/annotatable.py
@@ -4,9 +4,6 @@ Mixins for Annotatable model managers and serializers.
import abc
import logging
-from typing import (
- Optional,
-)
from sqlalchemy.orm import scoped_session
@@ -23,7 +20,7 @@ log = logging.getLogger(__name__)
# needed to extract this for use in manager *and* serializer, ideally, would use self.manager.annotation
# from serializer, but history_contents has no self.manager
# TODO: fix
-def _match_by_user(item, user) -> Optional[str]:
+def _match_by_user(item, user) -> str | None:
if not user:
return None
for annotation in item.annotations:
@@ -39,7 +36,7 @@ class AnnotatableManagerMixin:
@abc.abstractmethod
def session(self) -> scoped_session: ...
- def annotation(self, item) -> Optional[str]:
+ def annotation(self, item) -> str | None:
"""
Return the annotation string made by the `item`'s owner or `None` if there
is no annotation.
@@ -109,7 +106,7 @@ class AnnotatableDeserializerMixin:
class AnnotatableFilterMixin:
fn_filter_parsers: FunctionFilterParsersType
- def _owner_annotation(self, item) -> Optional[str]:
+ def _owner_annotation(self, item) -> str | None:
"""
Get the annotation by the item's owner.
"""
diff --git a/lib/galaxy/managers/base.py b/lib/galaxy/managers/base.py
index 2dc9e4feda2..e3df51c2668 100644
--- a/lib/galaxy/managers/base.py
+++ b/lib/galaxy/managers/base.py
@@ -36,10 +36,8 @@ from typing import (
Any,
Generic,
NamedTuple,
- Optional,
TYPE_CHECKING,
TypeVar,
- Union,
)
import sqlalchemy
@@ -79,7 +77,7 @@ class ParsedFilter(NamedTuple):
parsed_filter = ParsedFilter
-OrmFilterParserType = Union[None, dict[str, Any], Callable]
+OrmFilterParserType = None | dict[str, Any] | Callable
OrmFilterParsersType = dict[str, OrmFilterParserType]
FunctionFilterParserType = dict[str, Any]
FunctionFilterParsersType = dict[str, Any]
@@ -149,17 +147,17 @@ def get_class(class_name):
return item_class
-def decode_id(app: BasicSharedApp, id: Any, kind: Optional[str] = None) -> int:
+def decode_id(app: BasicSharedApp, id: Any, kind: str | None = None) -> int:
# note: use str - occasionally a fully numeric id will be placed in post body and parsed as int via JSON
# resulting in error for valid id
return decode_with_security(app.security, id, kind=kind)
-def decode_with_security(security: IdEncodingHelper, id: Any, kind: Optional[str] = None):
+def decode_with_security(security: IdEncodingHelper, id: Any, kind: str | None = None):
return security.decode_id(str(id), kind=kind)
-def encode_with_security(security: IdEncodingHelper, id: Any, kind: Optional[str] = None):
+def encode_with_security(security: IdEncodingHelper, id: Any, kind: str | None = None):
return security.encode_id(id, kind=kind)
@@ -169,7 +167,7 @@ def get_object(
class_name,
check_ownership: bool = False,
check_accessible: bool = False,
- deleted: Union[bool, None] = None,
+ deleted: bool | None = None,
):
"""
Convenience method to get a model object with the specified checks. This is
@@ -236,8 +234,8 @@ class ModelManager(Generic[U]):
eagerloads: bool = True,
filters=None,
order_by=None,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
+ limit: int | None = None,
+ offset: int | None = None,
) -> Query:
"""
Return a basic query from model_class, filters, order_by, and limit and offset.
@@ -251,7 +249,7 @@ class ModelManager(Generic[U]):
return self._filter_and_order_query(query, filters=filters, order_by=order_by, limit=limit, offset=offset)
def _filter_and_order_query(
- self, query: Query, filters=None, order_by=None, limit: Optional[int] = None, offset: Optional[int] = None
+ self, query: Query, filters=None, order_by=None, limit: int | None = None, offset: int | None = None
) -> Query:
# TODO: not a lot of functional cohesion here
query = self._apply_orm_filters(query, filters)
@@ -294,7 +292,7 @@ class ModelManager(Generic[U]):
"""
return (self.model_class.__table__.c.create_time,)
- def _apply_orm_limit_offset(self, query: Query, limit: Optional[int], offset: Optional[int]) -> Query:
+ def _apply_orm_limit_offset(self, query: Query, limit: int | None, offset: int | None) -> Query:
"""
Return the query after applying the given limit and offset (if not None).
"""
@@ -409,7 +407,7 @@ class ModelManager(Generic[U]):
orm_filters.append(filter_.filter)
return (orm_filters, fn_filters)
- def _orm_list(self, query: Optional[Query] = None, **kwargs) -> builtins.list[U]:
+ def _orm_list(self, query: Query | None = None, **kwargs) -> builtins.list[U]:
"""
Sends kwargs to build the query return all models found.
"""
@@ -626,7 +624,7 @@ class ModelSerializer(HasAModelManager[T]):
item_dict = MySerializer.serialize( my_item, keys_to_serialize )
"""
- default_view: Optional[str]
+ default_view: str | None
views: dict[str, list[str]]
def __init__(self, app: MinimalManagerApp, **kwargs):
@@ -810,7 +808,7 @@ class ModelValidator:
"""
@staticmethod
- def matches_type(key: str, val: Any, types: Union[type, tuple[Union[type, tuple[Any, ...]], ...]]):
+ def matches_type(key: str, val: Any, types: type | tuple[type | tuple[Any, ...], ...]):
"""
Check `val` against the type (or tuple of types) in `types`.
@@ -838,7 +836,7 @@ class ModelValidator:
return ModelValidator.matches_type(key, val, ((str,), type(None)))
@staticmethod
- def int_range(key: str, val: Any, min: Optional[int] = None, max: Optional[int] = None) -> int:
+ def int_range(key: str, val: Any, min: int | None = None, max: int | None = None) -> int:
"""
Must be a int between min and max.
"""
@@ -1153,7 +1151,7 @@ class ModelFilterParser(HasAModelManager):
return self.parsed_filter(filter_type="function", filter=lambda i: filter_fn(i, val))
# ---- ORM filters
- def _parse_orm_filter(self, attr, op, val) -> Optional[ParsedFilter]:
+ def _parse_orm_filter(self, attr, op, val) -> ParsedFilter | None:
"""
Attempt to parse a ORM-based filter.
@@ -1282,7 +1280,7 @@ class ModelFilterParser(HasAModelManager):
return any(filter.filter_type == "function" for filter in filters)
-def parse_bool(bool_string: Union[str, bool]) -> bool:
+def parse_bool(bool_string: str | bool) -> bool:
"""
Parse a boolean from a string.
"""
@@ -1326,9 +1324,9 @@ class StorageCleanerManager(Protocol):
def get_discarded(
self,
user: model.User,
- offset: Optional[int],
- limit: Optional[int],
- order: Optional[StoredItemOrderBy],
+ offset: int | None,
+ limit: int | None,
+ order: StoredItemOrderBy | None,
) -> list[StoredItem]:
"""Returns a paginated list of items deleted by the given user that are not yet purged."""
raise NotImplementedError
@@ -1344,9 +1342,9 @@ class StorageCleanerManager(Protocol):
def get_archived(
self,
user: model.User,
- offset: Optional[int],
- limit: Optional[int],
- order: Optional[StoredItemOrderBy],
+ offset: int | None,
+ limit: int | None,
+ order: StoredItemOrderBy | None,
) -> list[StoredItem]:
"""Returns a paginated list of items archived by the given user that are not yet purged."""
raise NotImplementedError
diff --git a/lib/galaxy/managers/chat.py b/lib/galaxy/managers/chat.py
index e41f34d8c11..1ac79d1abe5 100644
--- a/lib/galaxy/managers/chat.py
+++ b/lib/galaxy/managers/chat.py
@@ -2,8 +2,6 @@ import json
import logging
from typing import (
Any,
- Optional,
- Union,
)
log = logging.getLogger(__name__)
@@ -45,7 +43,7 @@ class ChatManager:
Business logic for chat exchanges.
"""
- def create(self, trans: ProvidesUserContext, job_id: Optional[int], message: str) -> ChatExchange:
+ def create(self, trans: ProvidesUserContext, job_id: int | None, message: str) -> ChatExchange:
"""
Create a new chat exchange in the DB. Currently these are *only* job-based chat exchanges, will need to generalize down the road.
:param job_id: id of the job to associate the response with
@@ -68,8 +66,8 @@ class ChatManager:
return chat_exchange
def resolve_page_from_interface_context(
- self, trans: ProvidesUserContext, query_context: Optional[dict[str, Any]]
- ) -> tuple[Optional[int], Optional["Page"]]:
+ self, trans: ProvidesUserContext, query_context: dict[str, Any] | None
+ ) -> tuple[int | None, Page | None]:
"""Extract and validate a page from an interface_context notebook payload.
Swallows only ID-decode failures; access-control errors propagate.
@@ -229,7 +227,7 @@ class ChatManager:
trans.sa_session.commit()
return chat_message
- def get(self, trans: ProvidesUserContext, job_id: int) -> Union[ChatExchange, None]:
+ def get(self, trans: ProvidesUserContext, job_id: int) -> ChatExchange | None:
"""
Returns the chat exchange from the DB based on the given job id.
:param job_id: id of the job to load a response for from the DB
@@ -251,7 +249,7 @@ class ChatManager:
raise InternalServerError(f"Error loading from the database: {unicodify(e)}")
return chat_exchange
- def get_exchange_by_id(self, trans: ProvidesUserContext, exchange_id: int) -> Union[ChatExchange, None]:
+ def get_exchange_by_id(self, trans: ProvidesUserContext, exchange_id: int) -> ChatExchange | None:
"""
Returns the chat exchange from the DB based on the exchange id.
:param exchange_id: id of the chat exchange to load from the DB
diff --git a/lib/galaxy/managers/citations.py b/lib/galaxy/managers/citations.py
index d714fd93d54..ebed5a43e8d 100644
--- a/lib/galaxy/managers/citations.py
+++ b/lib/galaxy/managers/citations.py
@@ -1,9 +1,6 @@
import functools
import logging
-from typing import (
- Optional,
- Union,
-)
+from typing import Union
from beaker.cache import CacheManager
from beaker.util import parse_cache_config_options
@@ -22,7 +19,7 @@ from galaxy.util import (
log = logging.getLogger(__name__)
CitationT = Union["BibtexCitation", "DoiCitation"]
-OptionalCitationT = Optional[CitationT]
+OptionalCitationT = CitationT | None
class CitationsManager:
@@ -156,7 +153,6 @@ BIBTEX_UNSET = object()
class DoiCitation(BaseCitation):
-
def __init__(self, citation_model: Citation, citation_manager: CitationsManager):
self.__doi = citation_model.content
self.doi_cache = citation_manager.doi_cache
diff --git a/lib/galaxy/managers/collections.py b/lib/galaxy/managers/collections.py
index ef1fd924b2f..053df8fe35f 100644
--- a/lib/galaxy/managers/collections.py
+++ b/lib/galaxy/managers/collections.py
@@ -2,7 +2,6 @@ import logging
from typing import (
Any,
Literal,
- Optional,
overload,
TYPE_CHECKING,
Union,
@@ -196,7 +195,7 @@ class DatasetCollectionManager:
flush=True,
completed_job=None,
output_name=None,
- fields: Optional[Union[str, list["FieldDict"]]] = None,
+ fields: str | list["FieldDict"] | None = None,
column_definitions=None,
rows=None,
) -> "DatasetCollectionInstance":
@@ -261,10 +260,9 @@ class DatasetCollectionManager:
flush: bool = True,
) -> "DatasetCollectionInstance":
if isinstance(parent, model.History):
- dataset_collection_instance: Union[
- model.HistoryDatasetCollectionAssociation,
- model.LibraryDatasetCollectionAssociation,
- ] = model.HistoryDatasetCollectionAssociation(
+ dataset_collection_instance: (
+ model.HistoryDatasetCollectionAssociation | model.LibraryDatasetCollectionAssociation
+ ) = model.HistoryDatasetCollectionAssociation(
collection=dataset_collection,
name=name,
)
@@ -316,7 +314,7 @@ class DatasetCollectionManager:
hide_source_items: bool = False,
copy_elements: bool = False,
history=None,
- fields: Optional[Union[str, list["FieldDict"]]] = None,
+ fields: str | list["FieldDict"] | None = None,
column_definitions=None,
rows=None,
) -> DatasetCollection:
@@ -497,7 +495,7 @@ class DatasetCollectionManager:
source: Literal[HistoryContentSource.hdca],
encoded_source_id,
copy_elements: bool = False,
- dataset_instance_attributes: Optional[dict[str, Any]] = None,
+ dataset_instance_attributes: dict[str, Any] | None = None,
):
"""
PRECONDITION: security checks on ability to add to parent occurred
diff --git a/lib/galaxy/managers/configuration.py b/lib/galaxy/managers/configuration.py
index bb2c597896c..ae07277d618 100644
--- a/lib/galaxy/managers/configuration.py
+++ b/lib/galaxy/managers/configuration.py
@@ -191,7 +191,9 @@ class ConfigSerializer(base.ModelSerializer):
"aws_estimate": _use_config,
"carbon_emission_estimates": _defaults_to(True),
"carbon_intensity": lambda item, key, **context: self.app.carbon_intensity,
- "geographical_server_location_name": lambda item, key, **context: self.app.geographical_server_location_name,
+ "geographical_server_location_name": lambda item, key, **context: (
+ self.app.geographical_server_location_name
+ ),
"geographical_server_location_code": _use_config,
"power_usage_effectiveness": _use_config,
"message_box_content": _use_config,
@@ -219,8 +221,12 @@ class ConfigSerializer(base.ModelSerializer):
"quota_source_labels": lambda item, key, **context: list(
object_store.get_quota_source_map().get_quota_source_labels()
),
- "object_store_allows_id_selection": lambda item, key, **context: object_store.object_store_allows_id_selection(),
- "object_store_ids_allowing_selection": lambda item, key, **context: object_store.object_store_ids_allowing_selection(),
+ "object_store_allows_id_selection": lambda item, key, **context: (
+ object_store.object_store_allows_id_selection()
+ ),
+ "object_store_ids_allowing_selection": lambda item, key, **context: (
+ object_store.object_store_ids_allowing_selection()
+ ),
"object_store_always_respect_user_selection": _use_config,
"user_activation_on": _use_config,
"user_library_import_dir_available": lambda item, key, **context: bool(item.get("user_library_import_dir")),
@@ -248,8 +254,9 @@ class ConfigSerializer(base.ModelSerializer):
"enable_tool_generated_tours": _use_config,
"sentry_dsn_public": lambda item, key, **context: item.sentry_dsn_public,
"sentry_client_traces_sample_rate": _use_config,
- "enable_webhooks": lambda item, key, **context: hasattr(self.app, "webhooks_registry")
- and bool(self.app.webhooks_registry.webhooks),
+ "enable_webhooks": lambda item, key, **context: (
+ hasattr(self.app, "webhooks_registry") and bool(self.app.webhooks_registry.webhooks)
+ ),
}
diff --git a/lib/galaxy/managers/context.py b/lib/galaxy/managers/context.py
index 374d506e4e0..30f8ed17bce 100644
--- a/lib/galaxy/managers/context.py
+++ b/lib/galaxy/managers/context.py
@@ -46,7 +46,6 @@ from typing import (
Any,
cast,
Literal,
- Optional,
)
from sqlalchemy import select
@@ -85,7 +84,7 @@ class ProvidesAppContext:
@property
@abc.abstractmethod
- def url_builder(self) -> Optional[Callable[..., str]]:
+ def url_builder(self) -> Callable[..., str] | None:
"""
Provide access to Galaxy URLs (if available).
@@ -207,8 +206,8 @@ class ProvidesUserContext(ProvidesAppContext):
"""
workflow_building_mode: Literal[1, True, False] = False
- galaxy_session: Optional[GalaxySession] = None
- _tag_handler: Optional[GalaxyTagHandlerSession] = None
+ galaxy_session: GalaxySession | None = None
+ _tag_handler: GalaxyTagHandlerSession | None = None
_short_term_cache: dict[tuple[Hashable, ...], Any]
def set_cache_value(self, args: tuple[Hashable, ...], value: Any):
@@ -251,8 +250,8 @@ class ProvidesUserContext(ProvidesAppContext):
"""Provide access to a user's personal vault."""
return UserVaultWrapper(self.app.vault, self.user)
- def get_user(self) -> Optional[User]:
- user = cast(Optional[User], self.user or self.galaxy_session and self.galaxy_session.user)
+ def get_user(self) -> User | None:
+ user = cast(User | None, self.user or self.galaxy_session and self.galaxy_session.user)
return user
@property
@@ -289,7 +288,7 @@ class ProvidesUserContext(ProvidesAppContext):
raise UserActivationRequiredException()
@property
- def user_ftp_dir(self) -> Optional[str]:
+ def user_ftp_dir(self) -> str | None:
base_dir = self.app.config.ftp_upload_dir
if base_dir is None or self.user is None:
return None
@@ -317,13 +316,13 @@ class ProvidesHistoryContext(ProvidesUserContext):
@property
@abc.abstractmethod
- def history(self) -> Optional[History]:
+ def history(self) -> History | None:
"""Provide access to the user's current history model object.
:rtype: Optional[galaxy.model.History]
"""
- def db_dataset_for(self, dbkey) -> Optional[HistoryDatasetAssociation]:
+ def db_dataset_for(self, dbkey) -> HistoryDatasetAssociation | None:
"""Optionally return the db_file dataset associated/needed by `dataset`."""
# If no history, return None.
if self.history is None:
diff --git a/lib/galaxy/managers/credentials.py b/lib/galaxy/managers/credentials.py
index 688ed3980fc..bfeba5634ab 100644
--- a/lib/galaxy/managers/credentials.py
+++ b/lib/galaxy/managers/credentials.py
@@ -1,8 +1,4 @@
import logging
-from typing import (
- Optional,
- Union,
-)
from sqlalchemy import select
from sqlalchemy.orm import scoped_session
@@ -32,7 +28,7 @@ from galaxy.util import now
log = logging.getLogger(__name__)
-CredentialsModelsSet = set[Union[UserCredentials, CredentialsGroup, Credential]]
+CredentialsModelsSet = set[UserCredentials | CredentialsGroup | Credential]
CredentialsAssociation = list[tuple[UserCredentials, CredentialsGroup, Credential]]
@@ -56,13 +52,13 @@ def build_credentials_context_response(
def _build_user_credentials_query(
user_id: DecodedDatabaseIdField,
- source_type: Optional[str] = None,
- source_id: Optional[str] = None,
- source_version: Optional[str] = None,
- service_name: Optional[str] = None,
- service_version: Optional[str] = None,
- user_credentials_id: Optional[DecodedDatabaseIdField] = None,
- group_id: Optional[DecodedDatabaseIdField] = None,
+ source_type: str | None = None,
+ source_id: str | None = None,
+ source_version: str | None = None,
+ service_name: str | None = None,
+ service_version: str | None = None,
+ user_credentials_id: DecodedDatabaseIdField | None = None,
+ group_id: DecodedDatabaseIdField | None = None,
current_group_only: bool = False,
):
"""
@@ -130,11 +126,11 @@ class CredentialsManager:
def get_user_credentials(
self,
user_id: DecodedDatabaseIdField,
- source_type: Optional[SOURCE_TYPE] = None,
- source_id: Optional[str] = None,
- source_version: Optional[str] = None,
- user_credentials_id: Optional[DecodedDatabaseIdField] = None,
- group_id: Optional[DecodedDatabaseIdField] = None,
+ source_type: SOURCE_TYPE | None = None,
+ source_id: str | None = None,
+ source_version: str | None = None,
+ user_credentials_id: DecodedDatabaseIdField | None = None,
+ group_id: DecodedDatabaseIdField | None = None,
) -> CredentialsAssociation:
stmt = _build_user_credentials_query(
user_id=user_id,
@@ -216,7 +212,7 @@ class CredentialsManager:
def update_credential(
self,
credential: Credential,
- value: Optional[str] = None,
+ value: str | None = None,
is_secret: bool = False,
) -> None:
credential.is_set = bool(value)
@@ -227,7 +223,7 @@ class CredentialsManager:
self,
group_id: DecodedDatabaseIdField,
name: str,
- value: Optional[str] = None,
+ value: str | None = None,
is_secret: bool = False,
) -> None:
credential = Credential(
@@ -243,7 +239,7 @@ class CredentialsManager:
def update_current_group(
self,
user_credentials: UserCredentials,
- group_id: Optional[DecodedDatabaseIdField] = None,
+ group_id: DecodedDatabaseIdField | None = None,
) -> None:
user_credentials.current_group_id = group_id
self.session.add(user_credentials)
diff --git a/lib/galaxy/managers/dataset_storage_operations.py b/lib/galaxy/managers/dataset_storage_operations.py
index f6d814315cd..b8de87ed431 100644
--- a/lib/galaxy/managers/dataset_storage_operations.py
+++ b/lib/galaxy/managers/dataset_storage_operations.py
@@ -10,7 +10,6 @@ from typing import (
cast,
Optional,
TYPE_CHECKING,
- Union,
)
from uuid import UUID
@@ -90,7 +89,7 @@ TERMINAL_RUN_STATES = {
StorageOperationRunState.failed.value,
}
-StorageOperationContent = Union[HistoryDatasetAssociation, HistoryDatasetCollectionAssociation]
+StorageOperationContent = HistoryDatasetAssociation | HistoryDatasetCollectionAssociation
@dataclass(frozen=True)
@@ -124,7 +123,7 @@ class StorageOperationPreviewComputation:
target_quota_delta: int
quota_delta_transfers: list[StorageOperationQuotaDeltaTransfer]
privacy_downgrade_count: int
- target_quota_projection: Optional[TargetQuotaProjection] = None
+ target_quota_projection: TargetQuotaProjection | None = None
class DatasetStorageOperationManager:
@@ -133,7 +132,7 @@ class DatasetStorageOperationManager:
def __init__(
self,
object_store: BaseObjectStore,
- config: Optional[GalaxyAppConfiguration] = None,
+ config: GalaxyAppConfiguration | None = None,
hdca_manager: Optional["HDCAManager"] = None,
):
self.object_store = object_store
@@ -158,7 +157,7 @@ class DatasetStorageOperationManager:
user: User,
dataset: Dataset,
target_object_store_id: str,
- ) -> Optional[DatasetStorageOperationFailureReasonCode]:
+ ) -> DatasetStorageOperationFailureReasonCode | None:
target_device_id = self._device_id_for_store(target_object_store_id)
if target_device_id is None:
return DatasetStorageOperationFailureReasonCode.invalid_target_object_store
@@ -189,8 +188,8 @@ class DatasetStorageOperationManager:
def target_quota_delta(
self,
dataset_size: int,
- source_quota_label: Optional[str],
- target_quota_label: Optional[str],
+ source_quota_label: str | None,
+ target_quota_label: str | None,
) -> int:
if source_quota_label == target_quota_label:
return 0
@@ -204,7 +203,7 @@ class DatasetStorageOperationManager:
target_quota_delta: int,
*,
additional_target_usage: int = 0,
- ) -> Optional[TargetQuotaProjection]:
+ ) -> TargetQuotaProjection | None:
if target_quota_delta <= 0:
return None
@@ -286,25 +285,25 @@ class DatasetStorageOperationManager:
return True
return source_device_id != target_device_id
- def _device_id_for_store(self, object_store_id: Optional[str]) -> Optional[str]:
+ def _device_id_for_store(self, object_store_id: str | None) -> str | None:
if object_store_id is None:
return None
return self.object_store.get_device_source_map().get_device_id(object_store_id)
- def _is_private_for_dataset(self, dataset: Dataset) -> Optional[bool]:
+ def _is_private_for_dataset(self, dataset: Dataset) -> bool | None:
try:
return self.object_store.is_private(dataset)
except Exception:
return None
- def _is_private_for_object_store_id(self, object_store_id: str) -> Optional[bool]:
+ def _is_private_for_object_store_id(self, object_store_id: str) -> bool | None:
try:
proxy = SimpleNamespace(object_store_id=object_store_id)
return self.object_store.is_private(proxy)
except Exception:
return None
- def _target_remaining_lifetime(self, dataset: Dataset, target_object_store_id: str) -> Optional[timedelta]:
+ def _target_remaining_lifetime(self, dataset: Dataset, target_object_store_id: str) -> timedelta | None:
expiration_days = self._target_store_expiration_days(target_object_store_id)
if expiration_days is None or dataset.create_time is None:
return None
@@ -312,7 +311,7 @@ class DatasetStorageOperationManager:
expiration_time = dataset.create_time + timedelta(days=expiration_days)
return expiration_time - now()
- def _target_store_expiration_days(self, target_object_store_id: str) -> Optional[int]:
+ def _target_store_expiration_days(self, target_object_store_id: str) -> int | None:
concrete_store = self.object_store.get_concrete_store_by_object_store_id(target_object_store_id)
if concrete_store is None:
return None
@@ -490,7 +489,7 @@ class DatasetStorageOperationManager:
decode_id: Callable[[str], int],
offset: int = 0,
limit: int = 50,
- search: Optional[str] = None,
+ search: str | None = None,
) -> tuple[list[StorageOperationRunItemStatus], int]:
return self._run_manager.get_run_items(
sa_session=sa_session,
@@ -509,7 +508,7 @@ class DatasetStorageOperationManager:
app: "MinimalManagerApp",
run: DatasetStorageOperationRun,
user: User,
- current_task_id: Optional[str] = None,
+ current_task_id: str | None = None,
) -> "StorageOperationRunExecutor":
return StorageOperationRunExecutor(
sa_session=sa_session,
@@ -857,7 +856,7 @@ class DatasetStorageOperationRunManager:
decode_id: Callable[[str], int],
offset: int = 0,
limit: int = 50,
- search: Optional[str] = None,
+ search: str | None = None,
) -> tuple[list[StorageOperationRunItemStatus], int]:
run_items_query = sa_session.query(DatasetStorageOperationRunItem).filter(
DatasetStorageOperationRunItem.run_id == run.id
@@ -973,7 +972,7 @@ class StorageOperationRunExecutor:
app: "MinimalManagerApp",
run: DatasetStorageOperationRun,
user: User,
- current_task_id: Optional[str],
+ current_task_id: str | None,
storage_operation_manager: DatasetStorageOperationManager,
):
self.sa_session = sa_session
@@ -1003,9 +1002,9 @@ class StorageOperationRunExecutor:
self.run_items_by_dataset_id_cache: dict[int, DatasetStorageOperationRunItem] = {}
self._pending_dataset_update_ids: set[int] = set()
# Cleanups queued during transfer; executed after batch DB commit to ensure durability.
- self._pending_cleanups: list[tuple[DatasetObjectStoreProxy, Optional[str]]] = []
+ self._pending_cleanups: list[tuple[DatasetObjectStoreProxy, str | None]] = []
- def execute_run(self, snapshot: Optional[DatasetStorageOperationSnapshot]) -> StorageOperationExecutionResult:
+ def execute_run(self, snapshot: DatasetStorageOperationSnapshot | None) -> StorageOperationExecutionResult:
"""Validate snapshot, drive state transitions, execute all datasets, and return execution outcome."""
if snapshot is None:
return self._fail_run("Bulk storage run failed because its preview snapshot could not be found.")
@@ -1077,7 +1076,7 @@ class StorageOperationRunExecutor:
message=message,
)
- def _execute(self, resolved_dataset_ids: list[int]) -> Optional[tuple[int, int, int, int]]:
+ def _execute(self, resolved_dataset_ids: list[int]) -> tuple[int, int, int, int] | None:
for dataset_id in resolved_dataset_ids:
if not self._owns_run():
return None
@@ -1240,8 +1239,7 @@ class StorageOperationRunExecutor:
self.target_quota_source_label,
)
- reason_code = self._validate_dataset(dataset, quota_delta)
- if reason_code is not None:
+ if (reason_code := self._validate_dataset(dataset, quota_delta)) is not None:
self._record_ineligible(dataset_id, reason_code)
return
@@ -1251,7 +1249,7 @@ class StorageOperationRunExecutor:
self,
dataset: Dataset,
quota_delta: int,
- ) -> Optional[DatasetStorageOperationFailureReasonCode]:
+ ) -> DatasetStorageOperationFailureReasonCode | None:
reason = self.storage_operation_manager.validate_dataset_for_move(
self.app.security_agent,
self.user,
@@ -1304,7 +1302,7 @@ class StorageOperationRunExecutor:
return
for attempt in range(1, TRANSFER_RETRY_ATTEMPTS + 1):
- target_proxy_for_cleanup: Optional[DatasetObjectStoreProxy] = None
+ target_proxy_for_cleanup: DatasetObjectStoreProxy | None = None
try:
bytes_processed = 0
if requires_data_transfer:
@@ -1400,7 +1398,7 @@ class StorageOperationRunExecutor:
self,
dataset_id: int,
reason_code: DatasetStorageOperationFailureReasonCode,
- run_item: Optional[DatasetStorageOperationRunItem] = None,
+ run_item: DatasetStorageOperationRunItem | None = None,
) -> None:
self.failed_count += 1
self._add_run_item(
@@ -1437,7 +1435,7 @@ class StorageOperationRunExecutor:
*,
dataset_id: int,
state: str,
- reason_code: Optional[DatasetStorageOperationFailureReasonCode] = None,
+ reason_code: DatasetStorageOperationFailureReasonCode | None = None,
bytes_processed: int = 0,
) -> DatasetStorageOperationRunItem:
run_item = self.run_items_by_dataset_id_cache.get(dataset_id)
@@ -1487,8 +1485,7 @@ class StorageOperationRunExecutor:
preserve_symlinks=False,
)
- extra_files_path_name = dataset.extra_files_path_name
- if extra_files_path_name:
+ if extra_files_path_name := dataset.extra_files_path_name:
self._copy_extra_files(source_proxy, target_proxy, extra_files_path_name)
return int(dataset.get_total_size() or 0)
@@ -1591,7 +1588,7 @@ class StorageOperationRunExecutor:
def _cleanup_source_dataset_data(
self,
source_proxy: DatasetObjectStoreProxy,
- extra_files_path_name: Optional[str],
+ extra_files_path_name: str | None,
) -> None:
try:
self.app.object_store.delete(source_proxy)
@@ -1625,7 +1622,7 @@ class StorageOperationRunExecutor:
def _cleanup_target_dataset_data(
self,
target_proxy: DatasetObjectStoreProxy,
- extra_files_path_name: Optional[str],
+ extra_files_path_name: str | None,
) -> None:
try:
self.app.object_store.delete(target_proxy)
@@ -1658,8 +1655,7 @@ class StorageOperationRunExecutor:
def _finalize_cross_device_move(self, dataset: Dataset, target_object_store_id: str):
old_object_store_id = dataset.object_store_id
- quota_source_map = self.app.object_store.get_quota_source_map()
- if quota_source_map:
+ if quota_source_map := self.app.object_store.get_quota_source_map():
old_label = quota_source_map.get_quota_source_label(old_object_store_id)
new_label = quota_source_map.get_quota_source_label(target_object_store_id)
if old_label != new_label:
diff --git a/lib/galaxy/managers/datasets.py b/lib/galaxy/managers/datasets.py
index 40024bf4619..f41a4f1e8bf 100644
--- a/lib/galaxy/managers/datasets.py
+++ b/lib/galaxy/managers/datasets.py
@@ -7,7 +7,6 @@ import logging
import os
from typing import (
Any,
- Optional,
TypeVar,
)
@@ -98,7 +97,7 @@ class DatasetManager(
"""
self.error_unless_dataset_purge_allowed()
for dataset_id in request.dataset_ids:
- dataset: Optional[Dataset] = self.session().get(Dataset, dataset_id)
+ dataset: Dataset | None = self.session().get(Dataset, dataset_id)
if dataset and dataset.user_can_purge:
try:
dataset.full_delete()
@@ -116,7 +115,7 @@ class DatasetManager(
# .... accessibility
# datasets can implement the accessible interface, but accessibility is checked in an entirely different way
# than those resources that have a user attribute (histories, pages, etc.)
- def is_accessible(self, item: Any, user: Optional[model.User], **kwargs) -> bool:
+ def is_accessible(self, item: Any, user: model.User | None, **kwargs) -> bool:
"""
Is this dataset readable/viewable to user?
"""
@@ -358,7 +357,7 @@ class DatasetAssociationManager(
super().__init__(app)
self.dataset_manager = DatasetManager(app)
- def is_accessible(self, item: U, user: Optional[model.User], **kwargs: Any) -> bool:
+ def is_accessible(self, item: U, user: model.User | None, **kwargs: Any) -> bool:
"""
Is this DA accessible to `user`?
"""
@@ -672,7 +671,9 @@ class _UnflattenedMetadataDatasetAssociationSerializer(base.ModelSerializer[T],
# TODO: Replace string cast with https://github.com/pydantic/pydantic/pull/9137 on 24.1
"genome_build": lambda item, key, **context: str(item.dbkey) if item.dbkey is not None else None,
# derived (not mapped) attributes
- "data_type": lambda item, key, **context: f"{item.datatype.__class__.__module__}.{item.datatype.__class__.__name__}",
+ "data_type": lambda item, key, **context: (
+ f"{item.datatype.__class__.__module__}.{item.datatype.__class__.__name__}"
+ ),
"converted": self.serialize_converted_datasets,
# TODO: metadata/extra files
}
@@ -681,7 +682,7 @@ class _UnflattenedMetadataDatasetAssociationSerializer(base.ModelSerializer[T],
# because of that: we need to add a few keys that will use the default serializer
self.serializable_keyset.update(["name", "state", "tool_version", "extension", "visible", "dbkey"])
- def _proxy_to_dataset(self, serializer: Optional[base.Serializer] = None, proxy_key: Optional[str] = None):
+ def _proxy_to_dataset(self, serializer: base.Serializer | None = None, proxy_key: str | None = None):
# dataset associations are (rough) proxies to datasets - access their serializer using this remapping fn
# remapping done by either kwarg key: IOW dataset attr key (e.g. uuid)
# or by kwarg serializer: a function that's passed in (e.g. permissions)
diff --git a/lib/galaxy/managers/datatypes.py b/lib/galaxy/managers/datatypes.py
index 9ca591b833a..f49dec233e4 100644
--- a/lib/galaxy/managers/datatypes.py
+++ b/lib/galaxy/managers/datatypes.py
@@ -1,8 +1,3 @@
-from typing import (
- Optional,
- Union,
-)
-
from pydantic import TypeAdapter
from galaxy.datatypes._schema import (
@@ -19,8 +14,8 @@ from galaxy.datatypes.registry import Registry
def view_index(
- datatypes_registry: Registry, extension_only: Optional[bool] = True, upload_only: Optional[bool] = True
-) -> Union[list[DatatypeDetails], list[str]]:
+ datatypes_registry: Registry, extension_only: bool | None = True, upload_only: bool | None = True
+) -> list[DatatypeDetails] | list[str]:
if extension_only:
if upload_only:
return datatypes_registry.upload_file_formats
@@ -59,7 +54,7 @@ def view_mapping(datatypes_registry: Registry) -> DatatypesMap:
def view_types_and_mapping(
- datatypes_registry: Registry, extension_only: Optional[bool] = True, upload_only: Optional[bool] = True
+ datatypes_registry: Registry, extension_only: bool | None = True, upload_only: bool | None = True
) -> DatatypesCombinedMap:
return DatatypesCombinedMap(
datatypes=view_index(datatypes_registry, extension_only, upload_only),
@@ -105,8 +100,8 @@ def _get_edam_details(datatypes_registry: Registry, edam_ids: dict[str, str]) ->
def view_edam_formats(
- datatypes_registry: Registry, detailed: Optional[bool] = False
-) -> Union[dict[str, str], dict[str, dict[str, str]]]:
+ datatypes_registry: Registry, detailed: bool | None = False
+) -> dict[str, str] | dict[str, dict[str, str]]:
if detailed:
return _get_edam_details(datatypes_registry, datatypes_registry.edam_formats)
else:
@@ -114,8 +109,8 @@ def view_edam_formats(
def view_edam_data(
- datatypes_registry: Registry, detailed: Optional[bool] = False
-) -> Union[dict[str, str], dict[str, dict[str, str]]]:
+ datatypes_registry: Registry, detailed: bool | None = False
+) -> dict[str, str] | dict[str, dict[str, str]]:
if detailed:
return _get_edam_details(datatypes_registry, datatypes_registry.edam_data)
else:
@@ -123,7 +118,7 @@ def view_edam_data(
def view_visualization_mappings(
- datatypes_registry: Registry, datatype: Optional[str] = None
+ datatypes_registry: Registry, datatype: str | None = None
) -> DatatypeVisualizationMappingsList:
"""
Get datatype visualization mappings from the registry.
@@ -161,7 +156,7 @@ def view_visualization_mappings(
return TypeAdapter(DatatypeVisualizationMappingsList).validate_python(mappings)
-def get_preferred_visualization(datatypes_registry: Registry, datatype_extension: str) -> Optional[dict[str, str]]:
+def get_preferred_visualization(datatypes_registry: Registry, datatype_extension: str) -> dict[str, str] | None:
"""
Get the preferred visualization mapping for a specific datatype extension.
Returns a dictionary with 'visualization' and 'default_params' keys, or None if no mapping exists.
diff --git a/lib/galaxy/managers/dbkeys.py b/lib/galaxy/managers/dbkeys.py
index 3315dc050c0..68d6fe8820b 100644
--- a/lib/galaxy/managers/dbkeys.py
+++ b/lib/galaxy/managers/dbkeys.py
@@ -6,9 +6,6 @@ import logging
import os.path
import re
from json import loads
-from typing import (
- Optional,
-)
from sqlalchemy import select
@@ -23,7 +20,7 @@ from galaxy.util import (
log = logging.getLogger(__name__)
-def read_dbnames(filename: Optional[str]) -> list[tuple[str, str]]:
+def read_dbnames(filename: str | None) -> list[tuple[str, str]]:
"""Read build names from file"""
db_names: list[tuple[str, str]] = []
try:
diff --git a/lib/galaxy/managers/display_applications.py b/lib/galaxy/managers/display_applications.py
index 83f4a0e6941..3ee45d0a2b1 100644
--- a/lib/galaxy/managers/display_applications.py
+++ b/lib/galaxy/managers/display_applications.py
@@ -1,5 +1,4 @@
import logging
-from typing import Optional
from urllib.parse import unquote_plus
from pydantic import BaseModel
@@ -18,22 +17,22 @@ log = logging.getLogger(__name__)
class CreateLinkStep(BaseModel):
name: str
- state: Optional[str] = None
- ready: Optional[bool] = False
+ state: str | None = None
+ ready: bool | None = False
class CreateLinkFeedback(BaseModel):
- messages: Optional[list[tuple[str, str]]] = None
- refresh: Optional[bool] = False
- resource: Optional[str] = None
- preparable_steps: Optional[list[CreateLinkStep]] = None
+ messages: list[tuple[str, str]] | None = None
+ refresh: bool | None = False
+ resource: str | None = None
+ preparable_steps: list[CreateLinkStep] | None = None
class CreateLinkIncoming(BaseModel):
app_name: str
dataset_id: str
link_name: str
- kwd: Optional[dict[str, str]] = None
+ kwd: dict[str, str] | None = None
class Link(BaseModel):
@@ -50,8 +49,8 @@ class DisplayApplication(BaseModel):
class ReloadFeedback(BaseModel):
message: str
- reloaded: list[Optional[str]]
- failed: list[Optional[str]]
+ reloaded: list[str | None]
+ failed: list[str | None]
class DisplayApplicationsManager:
@@ -118,7 +117,7 @@ class DisplayApplicationsManager:
app_name: str,
dataset_id: str,
link_name: str,
- user_id: Optional[str] = None,
+ user_id: str | None = None,
**kwds,
) -> CreateLinkFeedback:
"""Access to external display applications"""
diff --git a/lib/galaxy/managers/executables.py b/lib/galaxy/managers/executables.py
index 9293eeeda49..86a250ef6f9 100644
--- a/lib/galaxy/managers/executables.py
+++ b/lib/galaxy/managers/executables.py
@@ -2,7 +2,6 @@
from typing import (
Any,
- Optional,
)
import yaml
@@ -11,7 +10,7 @@ from galaxy import exceptions
from galaxy.util import in_directory
-def artifact_class(trans, as_dict: dict[str, Any], allow_in_directory: Optional[str] = None):
+def artifact_class(trans, as_dict: dict[str, Any], allow_in_directory: str | None = None):
object_id = as_dict.get("object_id", None)
if as_dict.get("src", None) == "from_path":
workflow_path = as_dict.get("path")
diff --git a/lib/galaxy/managers/export_tracker.py b/lib/galaxy/managers/export_tracker.py
index 10c3f18831a..941f9b42e99 100644
--- a/lib/galaxy/managers/export_tracker.py
+++ b/lib/galaxy/managers/export_tracker.py
@@ -1,9 +1,5 @@
import json
from datetime import timedelta
-from typing import (
- Optional,
- Union,
-)
from pydantic import BaseModel
from sqlalchemy import (
@@ -58,7 +54,7 @@ class StoreExportTracker:
return export_association
def get_object_exports(
- self, object_id: int, object_type: ExportObjectType, limit: Optional[int] = None, offset: Optional[int] = None
+ self, object_id: int, object_type: ExportObjectType, limit: int | None = None, offset: int | None = None
) -> list[StoreExportAssociation]:
stmt = (
select(
@@ -82,7 +78,7 @@ class StoreExportTracker:
def get_user_exports(
self,
user_id: int,
- limit: Optional[int] = None,
+ limit: int | None = None,
days: int = 30,
) -> list[StoreExportAssociation]:
"""
@@ -120,7 +116,7 @@ class StoreExportTracker:
if export.export_metadata:
# Access dict directly - JSONType handles deserialization
# however old records might be JSON strings.
- metadata_value: Union[str, dict] = export.export_metadata
+ metadata_value: str | dict = export.export_metadata
if isinstance(metadata_value, str):
export_metadata = json.loads(metadata_value)
else:
diff --git a/lib/galaxy/managers/favorites.py b/lib/galaxy/managers/favorites.py
index bb1d263cf20..451d8d8152e 100644
--- a/lib/galaxy/managers/favorites.py
+++ b/lib/galaxy/managers/favorites.py
@@ -41,8 +41,7 @@ class FavoritesManager:
) -> dict[str, Any]:
favorites = self.get(user)
canonical_id = self._resolve_object_id(trans, user, object_type, raw_object_id)
- favorite_list = favorites[object_type.value]
- if canonical_id not in favorite_list:
+ if canonical_id not in (favorite_list := favorites[object_type.value]):
favorite_list.append(canonical_id)
favorites = self._save(trans, user, favorites, commit=commit)
return favorites
diff --git a/lib/galaxy/managers/file_source_instances.py b/lib/galaxy/managers/file_source_instances.py
index cd23211e798..b823200e97a 100644
--- a/lib/galaxy/managers/file_source_instances.py
+++ b/lib/galaxy/managers/file_source_instances.py
@@ -3,8 +3,6 @@ from typing import (
Any,
cast,
Literal,
- Optional,
- Union,
)
from uuid import uuid4
@@ -114,14 +112,14 @@ class UserFileSourceModel(BaseModel):
uuid: UUID4
uri_root: str
name: str
- description: Optional[str]
+ description: str | None
hidden: bool
active: bool
purged: bool
type: FileSourceTemplateType
template_id: str
template_version: int
- variables: Optional[dict[str, TemplateVariableValueType]]
+ variables: dict[str, TemplateVariableValueType] | None
secrets: list[str]
@@ -270,7 +268,7 @@ class FileSourceInstancesManager:
return self._to_model(trans, persisted_file_source)
def _get_and_validate_target_upgrade_template(
- self, persisted_file_source: UserFileSource, payload: Union[UpgradeInstancePayload, TestUpgradeInstancePayload]
+ self, persisted_file_source: UserFileSource, payload: UpgradeInstancePayload | TestUpgradeInstancePayload
) -> FileSourceTemplate:
template = self._get_template(persisted_file_source, payload.template_version)
validate_no_extra_variables_defined(payload.variables, template)
@@ -408,7 +406,7 @@ class FileSourceInstancesManager:
trans: ProvidesUserContext,
payload: CanTestPluginStatus,
template: FileSourceTemplate,
- ) -> tuple[Optional[TemplateParameters], Optional[PluginAspectStatus]]:
+ ) -> tuple[TemplateParameters | None, PluginAspectStatus | None]:
template_server_configuration = self._resolver.template_server_configuration(
trans.user, template.id, template.version
)
@@ -431,7 +429,7 @@ class FileSourceInstancesManager:
payload: CanTestPluginStatus,
template: FileSourceTemplate,
template_parameters: TemplateParameters,
- ) -> tuple[Optional[FileSourceConfiguration], PluginAspectStatus]:
+ ) -> tuple[FileSourceConfiguration | None, PluginAspectStatus]:
configuration = None
exception = None
try:
@@ -442,7 +440,7 @@ class FileSourceInstancesManager:
def _connection_status(
self, trans: ProvidesUserContext, target: CanTestPluginStatus, configuration: FileSourceConfiguration
- ) -> tuple[Optional[BaseFilesSource], PluginAspectStatus]:
+ ) -> tuple[BaseFilesSource | None, PluginAspectStatus]:
file_source = None
exception = None
if isinstance(target, (UpgradeTestTarget, UpdateTestTarget)):
@@ -492,7 +490,7 @@ class FileSourceInstancesManager:
return user_file_source
def _get_template(
- self, persisted_object_store: UserFileSource, template_version: Optional[int] = None
+ self, persisted_object_store: UserFileSource, template_version: int | None = None
) -> FileSourceTemplate:
catalog = self._catalog
target_template_version = template_version or persisted_object_store.template_version
@@ -546,7 +544,7 @@ class UserDefinedFileSourcesImpl(UserDefinedFileSources):
self._app_vault = vault
self._catalog = catalog
- def _user_file_source(self, uri: str) -> Optional[UserFileSource]:
+ def _user_file_source(self, uri: str) -> UserFileSource | None:
if "://" not in uri:
return None
uri_scheme, uri_rest = uri.split("://", 1)
@@ -560,7 +558,7 @@ class UserDefinedFileSourcesImpl(UserDefinedFileSources):
user_object_store: UserFileSource = self._sa_session.query(UserFileSource).filter(index_filter).one()
return user_object_store
- def _file_source_properties_from_uri(self, uri: str) -> Optional[dict[str, Any]]:
+ def _file_source_properties_from_uri(self, uri: str) -> dict[str, Any] | None:
user_file_source = self._user_file_source(uri)
if not user_file_source:
return None
@@ -599,7 +597,7 @@ class UserDefinedFileSourcesImpl(UserDefinedFileSources):
if user_object_store.user.username != user_context.username:
raise ItemOwnershipException("Your Galaxy user does not have access to the requested resource.")
- def find_best_match(self, url: str) -> Optional[FileSourceScore]:
+ def find_best_match(self, url: str) -> FileSourceScore | None:
files_source_properties = self._file_source_properties_from_uri(url)
if files_source_properties is None:
return None
@@ -616,7 +614,7 @@ class UserDefinedFileSourcesImpl(UserDefinedFileSources):
def _all_user_file_source_properties(self, user_context: FileSourcesUserContext) -> list[dict[str, Any]]:
username_filter = User.__table__.c.username == user_context.username
- user: Optional[User] = self._sa_session.query(User).filter(username_filter).one_or_none()
+ user: User | None = self._sa_session.query(User).filter(username_filter).one_or_none()
if user is None:
return []
all_file_source_properties: list[dict[str, Any]] = []
@@ -672,9 +670,9 @@ class UserDefinedFileSourcesImpl(UserDefinedFileSources):
self,
for_serialization: bool,
user_context: FileSourcesUserContext,
- browsable_only: Optional[bool] = False,
- include_kind: Optional[set[PluginKind]] = None,
- exclude_kind: Optional[set[PluginKind]] = None,
+ browsable_only: bool | None = False,
+ include_kind: set[PluginKind] | None = None,
+ exclude_kind: set[PluginKind] | None = None,
) -> list[dict[str, Any]]:
"""Write out user file sources as list of config dictionaries."""
if user_context.anonymous:
@@ -702,7 +700,7 @@ class UserDefinedFileSourcesImpl(UserDefinedFileSources):
def configuration_to_file_source_properties(
file_source_configuration: FileSourceConfiguration,
label: str,
- doc: Optional[str],
+ doc: str | None,
id: str,
) -> dict[str, Any]:
file_source_properties = file_source_configuration.model_dump()
diff --git a/lib/galaxy/managers/folders.py b/lib/galaxy/managers/folders.py
index 112294ade64..3ce08e7fb83 100644
--- a/lib/galaxy/managers/folders.py
+++ b/lib/galaxy/managers/folders.py
@@ -5,9 +5,7 @@ Manager and Serializer for Library Folders.
import logging
from dataclasses import dataclass
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
)
from sqlalchemy import (
@@ -206,7 +204,7 @@ class FolderManager:
folder_dict["update_time"] = folder.update_time
return folder_dict
- def create(self, trans, parent_folder_id: int, new_folder_name: str, new_folder_description: Optional[str] = None):
+ def create(self, trans, parent_folder_id: int, new_folder_name: str, new_folder_description: str | None = None):
"""
Create a new folder under the given folder.
@@ -400,7 +398,7 @@ class FolderManager:
trans,
folder: LibraryFolder,
payload: LibraryFolderContentsIndexQueryPayload,
- ) -> tuple[list[Union[LibraryFolder, LibraryDataset]], int]:
+ ) -> tuple[list[LibraryFolder | LibraryDataset], int]:
"""Retrieves the contents of the given folder that match the provided filters and pagination parameters.
Returns a tuple with the list of paginated contents and the total number of items contained in the folder."""
limit = payload.limit
@@ -412,7 +410,7 @@ class FolderManager:
is_admin=trans.user_is_admin,
)
- content_items: list[Union[LibraryFolder, LibraryDataset]] = []
+ content_items: list[LibraryFolder | LibraryDataset] = []
sub_folders_stmt = self._get_sub_folders_statement(sa_session, folder, security_params, payload)
total_sub_folders = get_count(sa_session, sub_folders_stmt)
if payload.order_by in FOLDER_SORT_COLUMN_MAP:
@@ -523,7 +521,7 @@ class FolderManager:
return stmt
def _filter_by_include_deleted(
- self, stmt, item_model, item_permissions_model, include_deleted: Optional[bool], security: SecurityParams
+ self, stmt, item_model, item_permissions_model, include_deleted: bool | None, security: SecurityParams
):
if include_deleted: # Admins or users with MODIFY permissions can see deleted contents
if not security.is_admin:
@@ -545,7 +543,7 @@ class FolderManager:
def build_folder_path(
self, sa_session: galaxy_scoped_session, folder: model.LibraryFolder
- ) -> list[tuple[int, Optional[str]]]:
+ ) -> list[tuple[int, str | None]]:
"""
Returns the folder path from root to the given folder.
diff --git a/lib/galaxy/managers/genomes.py b/lib/galaxy/managers/genomes.py
index 1915a23f144..feb3f45ec36 100644
--- a/lib/galaxy/managers/genomes.py
+++ b/lib/galaxy/managers/genomes.py
@@ -1,6 +1,5 @@
from typing import (
Any,
- Optional,
TYPE_CHECKING,
)
@@ -31,10 +30,10 @@ class GenomesManager:
self._app = app
self.genomes = app.genomes
- def get_dbkeys(self, user: Optional[User], chrom_info: bool) -> list[list[str]]:
+ def get_dbkeys(self, user: User | None, chrom_info: bool) -> list[list[str]]:
return self.genomes.get_dbkeys(user, chrom_info)
- def is_registered_dbkey(self, dbkey: str, user: Optional[User]) -> bool:
+ def is_registered_dbkey(self, dbkey: str, user: User | None) -> bool:
dbkeys = self.get_dbkeys(user, chrom_info=False)
for _, key in dbkeys:
if dbkey == key:
diff --git a/lib/galaxy/managers/group_roles.py b/lib/galaxy/managers/group_roles.py
index b8d59703bea..a9de4380db9 100644
--- a/lib/galaxy/managers/group_roles.py
+++ b/lib/galaxy/managers/group_roles.py
@@ -1,7 +1,4 @@
import logging
-from typing import (
- Optional,
-)
from sqlalchemy import select
@@ -76,7 +73,7 @@ class GroupRolesManager:
def _get_group_role(
self, trans: ProvidesAppContext, group: model.Group, role: model.Role
- ) -> Optional[model.GroupRoleAssociation]:
+ ) -> model.GroupRoleAssociation | None:
return get_group_role(trans.sa_session, group, role)
def _add_role_to_group(self, trans: ProvidesAppContext, group: model.Group, role: model.Role):
@@ -89,7 +86,7 @@ class GroupRolesManager:
trans.sa_session.commit()
-def get_group_role(session: galaxy_scoped_session, group, role) -> Optional[GroupRoleAssociation]:
+def get_group_role(session: galaxy_scoped_session, group, role) -> GroupRoleAssociation | None:
stmt = (
select(GroupRoleAssociation).where(GroupRoleAssociation.group == group).where(GroupRoleAssociation.role == role)
)
diff --git a/lib/galaxy/managers/group_users.py b/lib/galaxy/managers/group_users.py
index 04472046e34..79dd2453593 100644
--- a/lib/galaxy/managers/group_users.py
+++ b/lib/galaxy/managers/group_users.py
@@ -1,7 +1,4 @@
import logging
-from typing import (
- Optional,
-)
from sqlalchemy import select
@@ -79,7 +76,7 @@ class GroupUsersManager:
def _get_group_user(
self, trans: ProvidesAppContext, group: model.Group, user: model.User
- ) -> Optional[model.UserGroupAssociation]:
+ ) -> model.UserGroupAssociation | None:
return get_group_user(trans.sa_session, user, group)
def _add_user_to_group(self, trans: ProvidesAppContext, group: model.Group, user: model.User):
@@ -92,7 +89,7 @@ class GroupUsersManager:
trans.sa_session.commit()
-def get_group_user(session: galaxy_scoped_session, user, group) -> Optional[UserGroupAssociation]:
+def get_group_user(session: galaxy_scoped_session, user, group) -> UserGroupAssociation | None:
stmt = (
select(UserGroupAssociation).where(UserGroupAssociation.user == user).where(UserGroupAssociation.group == group)
)
diff --git a/lib/galaxy/managers/hdas.py b/lib/galaxy/managers/hdas.py
index bc7095205f6..deb52357270 100644
--- a/lib/galaxy/managers/hdas.py
+++ b/lib/galaxy/managers/hdas.py
@@ -10,9 +10,7 @@ import logging
import os
from typing import (
Any,
- Optional,
TYPE_CHECKING,
- Union,
)
from urllib.parse import quote_plus
@@ -131,7 +129,7 @@ class HDAManager(
return self.list(filters=filters)
# .... security and permissions
- def is_owner(self, item, user: Optional[model.User], current_history=None, **kwargs: Any) -> bool:
+ def is_owner(self, item, user: model.User | None, current_history=None, **kwargs: Any) -> bool:
"""
Use history to see if current user owns HDA.
"""
@@ -188,7 +186,7 @@ class HDAManager(
user_context=user_context,
)
if request.source == DatasetSourceType.hda:
- dataset_instance: Union[HistoryDatasetAssociation, LibraryDatasetDatasetAssociation] = self.get_accessible(
+ dataset_instance: HistoryDatasetAssociation | LibraryDatasetDatasetAssociation = self.get_accessible(
request.content, user
)
else:
@@ -362,7 +360,7 @@ class HDAManager(
def dereference_input_to_hda(
trans: ProvidesHistoryContext,
- data_request: Union[DataRequestUri, FileRequestUri],
+ data_request: DataRequestUri | FileRequestUri,
history: model.History,
) -> HistoryDatasetAssociation:
permissions = trans.app.security_agent.history_get_default_permissions(history)
@@ -420,9 +418,9 @@ class HDAStorageCleanerManager(base.StorageCleanerManager):
def get_discarded(
self,
user: model.User,
- offset: Optional[int],
- limit: Optional[int],
- order: Optional[StoredItemOrderBy],
+ offset: int | None,
+ limit: int | None,
+ order: StoredItemOrderBy | None,
) -> list[StoredItem]:
stmt = (
select(
@@ -488,7 +486,7 @@ class HDAStorageCleanerManager(base.StorageCleanerManager):
errors=errors,
)
- def _request_full_delete_all(self, dataset_ids_to_remove: set[int], user: Optional[model.User]):
+ def _request_full_delete_all(self, dataset_ids_to_remove: set[int], user: model.User | None):
use_tasks = self.dataset_manager.app.config.enable_celery_tasks
request = PurgeDatasetsTaskRequest(dataset_ids=list(dataset_ids_to_remove))
if use_tasks:
diff --git a/lib/galaxy/managers/hdcas.py b/lib/galaxy/managers/hdcas.py
index 7ec7b9d47f1..7dc0d556856 100644
--- a/lib/galaxy/managers/hdcas.py
+++ b/lib/galaxy/managers/hdcas.py
@@ -6,7 +6,6 @@ history.
"""
import logging
-from typing import Optional
from galaxy import model
from galaxy.exceptions import RequestParameterInvalidException
@@ -109,7 +108,7 @@ class HDCAManager(
self.map_datasets(content, fn=lambda item, *args: set_collection_attributes(item, payload.items()))
# .... security and permissions
- def is_owner(self, item: model.HistoryDatasetCollectionAssociation, user: Optional[model.User], **kwargs) -> bool:
+ def is_owner(self, item: model.HistoryDatasetCollectionAssociation, user: model.User | None, **kwargs) -> bool:
"""
Use history to see if current user owns HDCA.
"""
diff --git a/lib/galaxy/managers/headers_encryption.py b/lib/galaxy/managers/headers_encryption.py
index 2bff5233bb1..ebade7d3358 100644
--- a/lib/galaxy/managers/headers_encryption.py
+++ b/lib/galaxy/managers/headers_encryption.py
@@ -14,7 +14,6 @@ Header sensitivity is determined by the URL headers configuration file.
import logging
from typing import (
Any,
- Optional,
)
from galaxy.config.url_headers import UrlHeadersConfig
@@ -31,7 +30,7 @@ log = logging.getLogger(__name__)
def is_sensitive_header(
- header_name: str, url_headers_config: Optional[UrlHeadersConfig] = None, url: Optional[str] = None
+ header_name: str, url_headers_config: UrlHeadersConfig | None = None, url: str | None = None
) -> bool:
"""
Check if a header contains sensitive information and should be encrypted.
@@ -64,7 +63,7 @@ def is_sensitive_header(
def has_sensitive_headers(
- data: dict, url_headers_config: Optional[UrlHeadersConfig] = None, url: Optional[str] = None
+ data: dict, url_headers_config: UrlHeadersConfig | None = None, url: str | None = None
) -> bool:
"""
Check if the data structure contains any sensitive headers that would require encryption.
@@ -140,7 +139,7 @@ def has_sensitive_headers(
return check_sensitivity(data, url)
-def create_vault_key(context_id: str, header_name: str, key_prefix: Optional[str] = None) -> str:
+def create_vault_key(context_id: str, header_name: str, key_prefix: str | None = None) -> str:
"""
Create a vault key for storing a header value.
@@ -176,9 +175,9 @@ def encrypt_headers_in_data(
data: dict,
context_id: str,
vault: Vault,
- key_prefix: Optional[str] = None,
+ key_prefix: str | None = None,
reference_prefix: str = "VAULT_HEADER",
- url_headers_config: Optional[UrlHeadersConfig] = None,
+ url_headers_config: UrlHeadersConfig | None = None,
) -> dict:
"""
Recursively process data structure to encrypt sensitive headers.
@@ -239,9 +238,9 @@ def decrypt_headers_in_data(
data: dict,
context_id: str,
vault: Vault,
- key_prefix: Optional[str] = None,
+ key_prefix: str | None = None,
reference_prefix: str = "VAULT_HEADER",
- url_headers_config: Optional[UrlHeadersConfig] = None,
+ url_headers_config: UrlHeadersConfig | None = None,
) -> dict:
"""
Recursively process data structure to decrypt sensitive headers from vault.
@@ -291,10 +290,10 @@ def _encrypt_headers_dict(
headers: dict[str, str],
context_id: str,
vault: Vault,
- key_prefix: Optional[str] = None,
+ key_prefix: str | None = None,
reference_prefix: str = "VAULT_HEADER",
- url_headers_config: Optional[UrlHeadersConfig] = None,
- url: Optional[str] = None,
+ url_headers_config: UrlHeadersConfig | None = None,
+ url: str | None = None,
) -> dict[str, str]:
"""
Encrypt sensitive headers in a headers dictionary.
@@ -328,7 +327,7 @@ def _decrypt_headers_dict(
headers: dict[str, str],
context_id: str,
vault: Vault,
- key_prefix: Optional[str] = None,
+ key_prefix: str | None = None,
reference_prefix: str = "VAULT_HEADER",
) -> dict[str, str]:
"""
diff --git a/lib/galaxy/managers/histories.py b/lib/galaxy/managers/histories.py
index 83a9b7d94bb..8c64eeed574 100644
--- a/lib/galaxy/managers/histories.py
+++ b/lib/galaxy/managers/histories.py
@@ -11,9 +11,7 @@ from typing import (
Any,
cast,
Literal,
- Optional,
TYPE_CHECKING,
- Union,
)
from uuid import UUID
@@ -127,7 +125,7 @@ class HistoryManager(sharable.SharableModelManager[model.History], deletable.Pur
def index_query(
self, trans: ProvidesUserContext, payload: HistoryIndexQueryPayload, include_total_count: bool = False
- ) -> tuple["ScalarResult[model.History]", Union[int, None]]:
+ ) -> tuple["ScalarResult[model.History]", int | None]:
show_deleted = False
show_own = payload.show_own
show_published = payload.show_published
@@ -246,7 +244,7 @@ class HistoryManager(sharable.SharableModelManager[model.History], deletable.Pur
# .... sharable
# overriding to handle anonymous users' current histories in both cases
def by_user(
- self, user: model.User, current_history: Optional[model.History] = None, **kwargs: Any
+ self, user: model.User, current_history: model.History | None = None, **kwargs: Any
) -> list[model.History]:
"""
Get all the histories for a given user (allowing anon users' theirs)
@@ -260,8 +258,8 @@ class HistoryManager(sharable.SharableModelManager[model.History], deletable.Pur
def is_owner(
self,
item: model.Base,
- user: Optional[model.User],
- current_history: Optional[model.History] = None,
+ user: model.User | None,
+ current_history: model.History | None = None,
**kwargs: Any,
) -> bool:
"""
@@ -443,7 +441,7 @@ class HistoryManager(sharable.SharableModelManager[model.History], deletable.Pur
return job
def get_sharing_extra_information(
- self, trans, item, users: set[model.User], errors: set[str], option: Optional[sharable.SharingOptions] = None
+ self, trans, item, users: set[model.User], errors: set[str], option: sharable.SharingOptions | None = None
) -> ShareHistoryExtra:
"""Returns optional extra information about the datasets of the history that can be accessed by the users."""
extra = ShareHistoryExtra()
@@ -521,7 +519,7 @@ class HistoryManager(sharable.SharableModelManager[model.History], deletable.Pur
else:
log.warning(f"User without permissions tried to make dataset with id: {dataset.id} public")
- def archive_history(self, history: model.History, archive_export_id: Optional[int]):
+ def archive_history(self, history: model.History, archive_export_id: int | None):
"""Marks the history with the given id as archived and optionally associates it with the given archive export record.
**Important**: The caller is responsible for passing a valid `archive_export_id` that belongs to the given history.
@@ -590,9 +588,9 @@ class HistoryStorageCleanerManager(StorageCleanerManager):
def get_discarded(
self,
user: model.User,
- offset: Optional[int],
- limit: Optional[int],
- order: Optional[StoredItemOrderBy],
+ offset: int | None,
+ limit: int | None,
+ order: StoredItemOrderBy | None,
) -> list[StoredItem]:
stmt = select(model.History).where(
model.History.user_id == user.id,
@@ -625,9 +623,9 @@ class HistoryStorageCleanerManager(StorageCleanerManager):
def get_archived(
self,
user: model.User,
- offset: Optional[int],
- limit: Optional[int],
- order: Optional[StoredItemOrderBy],
+ offset: int | None,
+ limit: int | None,
+ order: StoredItemOrderBy | None,
) -> list[StoredItem]:
stmt = select(model.History).where(
model.History.user_id == user.id,
@@ -687,7 +685,7 @@ class HistoryExportManager:
self.app = app
self.export_tracker = export_tracker
- def get_task_exports(self, trans, history_id: int, limit: Optional[int] = None, offset: Optional[int] = None):
+ def get_task_exports(self, trans, history_id: int, limit: int | None = None, offset: int | None = None):
"""Returns task-based exports associated with this history"""
history = self._history(trans, history_id)
export_associations = self.export_tracker.get_object_exports(
@@ -701,8 +699,8 @@ class HistoryExportManager:
def create_export_association(self, history_id: int) -> model.StoreExportAssociation:
return self.export_tracker.create_export_association(object_id=history_id, object_type=self.export_object_type)
- def get_record_metadata(self, export: model.StoreExportAssociation) -> Optional[ExportObjectMetadata]:
- metadata: Union[dict, str, None] = export.export_metadata
+ def get_record_metadata(self, export: model.StoreExportAssociation) -> ExportObjectMetadata | None:
+ metadata: dict | str | None = export.export_metadata
if not metadata:
return None
if isinstance(metadata, str):
@@ -710,12 +708,11 @@ class HistoryExportManager:
assert isinstance(metadata, dict)
# Use model_construct to skip validation and avoid double-encoding of ID fields
request_data_raw = metadata.get("request_data", {})
- result_data_raw = metadata.get("result_data")
payload_raw = request_data_raw.get("payload")
if not payload_raw:
raise MessageException("Export metadata is missing payload information")
# Construct the appropriate payload model based on whether target_uri is present
- payload: Union[WriteStoreToPayload, ShortTermStoreExportPayload]
+ payload: WriteStoreToPayload | ShortTermStoreExportPayload
if "target_uri" in payload_raw:
payload = WriteStoreToPayload.model_construct(**payload_raw)
else:
@@ -732,7 +729,7 @@ class HistoryExportManager:
payload=payload,
)
result_data = None
- if result_data_raw:
+ if result_data_raw := metadata.get("result_data"):
result_data = ExportObjectResultMetadata.model_construct(
success=result_data_raw.get("success"),
uri=result_data_raw.get("uri"),
@@ -785,7 +782,7 @@ class HistoryExportManager:
rval = trans.security.encode_all_ids(rval)
return rval
- def get_ready_jeha(self, trans, history_id: int, jeha_id: Union[int, Literal["latest"]] = "latest"):
+ def get_ready_jeha(self, trans, history_id: int, jeha_id: int | Literal["latest"] = "latest"):
history = self._history(trans, history_id)
matching_exports = history.exports
if jeha_id != "latest":
diff --git a/lib/galaxy/managers/history_audit_monitor.py b/lib/galaxy/managers/history_audit_monitor.py
index 78a51e993a5..0377a755070 100644
--- a/lib/galaxy/managers/history_audit_monitor.py
+++ b/lib/galaxy/managers/history_audit_monitor.py
@@ -19,7 +19,6 @@ from collections.abc import Iterator
from datetime import timedelta
from typing import (
Any,
- Optional,
)
from sqlalchemy import select as sa_select
@@ -121,13 +120,13 @@ class HistoryAuditMonitor:
self.poll_interval: int = config.history_audit_monitor_poll_interval
self._is_postgres: bool = "postgres" in model.engine.name
self._exit = threading.Event()
- self._thread: Optional[threading.Thread] = None
+ self._thread: threading.Thread | None = None
self._active = False
# Bounded LRU cache: history_id -> (user_id, session_ids), refreshed on miss.
# For registered-owned histories: (user_id, ()); for anonymous histories:
# (None, (session_id, ...)) — a history can be associated with multiple
# sessions via GalaxySessionToHistoryAssociation.
- self._history_owner_cache: OrderedDict[int, tuple[Optional[int], tuple[int, ...]]] = OrderedDict()
+ self._history_owner_cache: OrderedDict[int, tuple[int | None, tuple[int, ...]]] = OrderedDict()
def start(self) -> None:
if self._active:
@@ -253,8 +252,7 @@ class HistoryAuditMonitor:
keeping this manager free of presentation concerns.
"""
# Resolve owners for unknown history_ids
- unknown = history_ids - self._history_owner_cache.keys()
- if unknown:
+ if unknown := history_ids - self._history_owner_cache.keys():
self._refresh_owner_cache(unknown)
user_updates: dict[str, list[int]] = defaultdict(list)
diff --git a/lib/galaxy/managers/history_contents.py b/lib/galaxy/managers/history_contents.py
index 27ef9f176e2..8dfbd15c20b 100644
--- a/lib/galaxy/managers/history_contents.py
+++ b/lib/galaxy/managers/history_contents.py
@@ -7,7 +7,6 @@ import json
import logging
from typing import (
Any,
- Optional,
)
from sqlalchemy import (
@@ -174,8 +173,7 @@ class HistoryContentsManager(base.SortableManager):
.where(HDA.history_id == history_id, HDA.hid == hid, HDA.visible == true())
.order_by(HDA.id.asc())
)
- result = session.execute(stmt).scalars().first()
- if result is not None:
+ if (result := session.execute(stmt).scalars().first()) is not None:
return result
not_a_conversion = ~select(ICDA.id).where(ICDA.hda_id == HDA.id).exists()
stmt = select(HDA).where(HDA.history_id == history_id, HDA.hid == hid, not_a_conversion).order_by(HDA.id.asc())
@@ -607,7 +605,7 @@ class HistoryContentsFilters(
# history. ``None`` means the filter is being parsed outside a history
# scope (e.g. ``/api/datasets``); in that case the HDCA branch of the
# extension filter degrades to a no-op (HDA filter still applies).
- _current_history_id: Optional[int] = None
+ _current_history_id: int | None = None
def parse_query_filters_with_relations(self, query_filters: ValueFilterQueryParams, history_id):
"""Parse query filters but consider case where related filter is included."""
diff --git a/lib/galaxy/managers/history_graph.py b/lib/galaxy/managers/history_graph.py
index 0106af82373..85624cdc6b9 100644
--- a/lib/galaxy/managers/history_graph.py
+++ b/lib/galaxy/managers/history_graph.py
@@ -9,8 +9,6 @@ import json
import logging
from typing import (
Literal,
- Optional,
- Union,
)
from sqlalchemy import (
@@ -71,7 +69,7 @@ MAX_LIMIT = 1000
SYNTHETIC_TOOL_IDS: tuple[str, ...] = ("__DATA_FETCH__",)
-def _summary_dict(summary) -> Optional[dict[str, int]]:
+def _summary_dict(summary) -> dict[str, int] | None:
"""Lift JobStateSummary (a NamedTuple) to a dict, or None."""
if summary is None or summary.all_jobs == 0:
return None
@@ -88,10 +86,10 @@ class HistoryGraphManager:
history_id: int,
limit: int = 500,
include_deleted: bool = False,
- seed: Optional[NodeRef] = None,
+ seed: NodeRef | None = None,
direction: Literal["backward", "forward", "both"] = "both",
depth: int = 5,
- seed_scope_hid: Optional[int] = None,
+ seed_scope_hid: int | None = None,
) -> HistoryGraphResponse:
return HistoryGraphBuilder(
sa_session=sa_session,
@@ -133,12 +131,12 @@ class HistoryGraphBuilder:
security: IdEncodingHelper,
history_id: int,
limit: int = 500,
- toolbox: Optional[AbstractToolBox] = None,
+ toolbox: AbstractToolBox | None = None,
include_deleted: bool = False,
- seed: Optional[NodeRef] = None,
+ seed: NodeRef | None = None,
direction: Literal["backward", "forward", "both"] = "both",
depth: int = 5,
- seed_scope_hid: Optional[int] = None,
+ seed_scope_hid: int | None = None,
):
self.sa_session = sa_session
self.security = security
@@ -150,8 +148,8 @@ class HistoryGraphBuilder:
self.direction = direction
self.depth = depth
self.seed_scope_hid = seed_scope_hid
- self._older_than_hid: Optional[int] = None
- self._newer_than_hid: Optional[int] = None
+ self._older_than_hid: int | None = None
+ self._newer_than_hid: int | None = None
self._sort_keys: dict[NodeRef, tuple[int, int]] = {}
def build(self) -> HistoryGraphResponse:
@@ -171,7 +169,7 @@ class HistoryGraphBuilder:
# 3. Producer lookup + payload input resolution.
edges: list[GraphEdge] = []
- tr_nodes: dict[int, Optional[str]] = {} # tr_id -> tool_id
+ tr_nodes: dict[int, str | None] = {} # tr_id -> tool_id
closure_dataset_ids: set[int] = set()
closure_collection_ids: set[int] = set()
@@ -318,7 +316,7 @@ class HistoryGraphBuilder:
def _filter_deleted_ids(
self,
- model_cls: Union[type[HistoryDatasetAssociation], type[HistoryDatasetCollectionAssociation]],
+ model_cls: type[HistoryDatasetAssociation] | type[HistoryDatasetCollectionAssociation],
ids: set[int],
) -> set[int]:
"""Return the subset of ``ids`` whose rows are not marked deleted.
@@ -602,7 +600,7 @@ class HistoryGraphBuilder:
for row in self.sa_session.execute(stmt)
]
- def _tr_nodes(self, tr_map: dict[int, Optional[str]]) -> list[GraphNode]:
+ def _tr_nodes(self, tr_map: dict[int, str | None]) -> list[GraphNode]:
return [self._node("tool_request", tr_id, tool_id=tool_id) for tr_id, tool_id in tr_map.items()]
def _resolve_tool_names(self, nodes: list[GraphNode]) -> None:
diff --git a/lib/galaxy/managers/interactivetool.py b/lib/galaxy/managers/interactivetool.py
index 21b872f146e..22b1461a75f 100644
--- a/lib/galaxy/managers/interactivetool.py
+++ b/lib/galaxy/managers/interactivetool.py
@@ -6,9 +6,7 @@ from collections.abc import (
)
from typing import (
Any,
- Optional,
TYPE_CHECKING,
- Union,
)
from urllib.parse import (
urlsplit,
@@ -75,10 +73,10 @@ class InteractiveToolPropagatorSQLAlchemy:
self,
key: str,
key_type: str,
- token: Union[str, None],
- host: Union[str, None],
- port: Union[int, None],
- info: Union[str, None] = None,
+ token: str | None,
+ host: str | None,
+ port: int | None,
+ info: str | None = None,
) -> None:
"""
Write out a key, key_type, token, value store that is can be used for coordinating with external resources.
@@ -152,7 +150,7 @@ class InteractiveToolManager:
def __init__(
self,
app: "MinimalManagerApp",
- dispatcher: Optional[SSEEventDispatcher] = None,
+ dispatcher: SSEEventDispatcher | None = None,
) -> None:
self.app = app
self.security = app.security
@@ -171,7 +169,7 @@ class InteractiveToolManager:
self.dispatcher = dispatcher if dispatcher is not None else app.resolve_or_none(SSEEventDispatcher)
def create_entry_points(
- self, job: Job, tool: "Tool", entry_points=Union[Iterable[dict[str, Any]], None], flush: bool = True
+ self, job: Job, tool: "Tool", entry_points=Iterable[dict[str, Any]] | None, flush: bool = True
) -> None:
entry_points = entry_points or tool.ports
for entry in entry_points:
@@ -254,7 +252,7 @@ class InteractiveToolManager:
stmt = stmt.where(Job.session_id == trans.galaxy_session.id)
return trans.sa_session.scalars(stmt)
- def can_access_job(self, trans: "ProvidesUserContext", job: Union[Job, None]) -> bool:
+ def can_access_job(self, trans: "ProvidesUserContext", job: Job | None) -> bool:
if job:
if trans.user is None:
galaxy_session = trans.galaxy_session
@@ -303,7 +301,7 @@ class InteractiveToolManager:
self.sa_session.commit()
self.propagator.remove_entry_point(entry_point)
- def target_if_active(self, trans, entry_point: InteractiveToolEntryPoint) -> Union[str, None]:
+ def target_if_active(self, trans, entry_point: InteractiveToolEntryPoint) -> str | None:
if entry_point.active and not entry_point.deleted:
use_it_proxy_host_cfg = (
not self.app.config.interactivetools_upstream_proxy and self.app.config.interactivetools_proxy_host
@@ -356,7 +354,7 @@ class InteractiveToolManager:
url_path += entry_point.entry_url.lstrip("/")
return url_path
- def access_entry_point_target(self, trans: "ProvidesUserContext", entry_point_id: int) -> Union[str, None]:
+ def access_entry_point_target(self, trans: "ProvidesUserContext", entry_point_id: int) -> str | None:
entry_point = self.sa_session.get(InteractiveToolEntryPoint, entry_point_id)
assert entry_point
if self.can_access_entry_point(trans, entry_point):
diff --git a/lib/galaxy/managers/jobs.py b/lib/galaxy/managers/jobs.py
index df5d4cf589c..e4d2f1c9edf 100644
--- a/lib/galaxy/managers/jobs.py
+++ b/lib/galaxy/managers/jobs.py
@@ -11,10 +11,8 @@ from pathlib import Path
from typing import (
Any,
cast,
- Optional,
TYPE_CHECKING,
TypeVar,
- Union,
)
import sqlalchemy
@@ -136,7 +134,7 @@ if TYPE_CHECKING:
log = logging.getLogger(__name__)
JobStateT = str
-JobStatesT = Union[JobStateT, Iterable[JobStateT]]
+JobStatesT = JobStateT | Iterable[JobStateT]
STDOUT_LOCATION = "outputs/tool_stdout"
@@ -166,7 +164,7 @@ def get_path_key(path_tuple: tuple):
return path_key
-def safe_label_or_none(label: str) -> Optional[str]:
+def safe_label_or_none(label: str) -> str | None:
if len(label) > 63:
return None
return label
@@ -370,7 +368,7 @@ class JobManager:
trans.sa_session.refresh(job)
return job
- def _user_can_access_job(self, job: Job, user: Optional[User]) -> bool:
+ def _user_can_access_job(self, job: Job, user: User | None) -> bool:
has_outputs = bool(job.output_datasets) or bool(job.output_dataset_collection_instances)
if has_outputs:
datasets_ok = all(
@@ -478,13 +476,13 @@ class JobSearch:
self,
user: User,
tool_id: str,
- tool_version: Optional[str],
+ tool_version: str | None,
param: ToolStateJobInstancePopulatedT,
param_dump: ToolStateDumpedToJsonInternalT,
- job_state: Optional[JobStatesT] = (Job.states.OK,),
- history_id: Union[int, None] = None,
+ job_state: JobStatesT | None = (Job.states.OK,),
+ history_id: int | None = None,
require_name_match: bool = True,
- ) -> Union[Job, None]:
+ ) -> Job | None:
"""Search for jobs producing same results using the 'inputs' part of a tool POST."""
input_data: dict[Any, list[dict[str, Any]]] = defaultdict(list)
@@ -534,15 +532,15 @@ class JobSearch:
def __search(
self,
tool_id: str,
- tool_version: Optional[str],
+ tool_version: str | None,
user: model.User,
input_data: dict[Any, list[dict[str, Any]]],
- job_state: Optional[JobStatesT],
+ job_state: JobStatesT | None,
param_dump: ToolStateDumpedToJsonInternalT,
wildcard_param_dump=None,
- history_id: Union[int, None] = None,
+ history_id: int | None = None,
require_name_match: bool = True,
- ) -> Union[Job, None]:
+ ) -> Job | None:
search_timer = ExecutionTimer()
def replace_dataset_ids(path, key, value):
@@ -678,10 +676,10 @@ class JobSearch:
stmt: "Select[tuple[int]]",
tool_id: str,
user_id: int,
- tool_version: Optional[str],
- job_state: Union[JobStatesT, None],
+ tool_version: str | None,
+ job_state: JobStatesT | None,
wildcard_param_dump,
- history_id: Union[int, None],
+ history_id: int | None,
) -> "Select[tuple[int]]":
"""Build subquery that selects a job with correct job parameters."""
# Apply job-level filters BEFORE the CTE so they are included in the
@@ -1604,7 +1602,7 @@ def _get_direct_job_metrics(sa_session: galaxy_scoped_session, invocation_id: in
def _get_job_metrics_recursive(
sa_session: galaxy_scoped_session,
invocation_id: int,
- parent_step_prefix: Optional[str] = None,
+ parent_step_prefix: str | None = None,
):
"""
Recursively get job metrics including subworkflows.
@@ -1859,7 +1857,7 @@ class JobsSummary(TypedDict):
id: int
-def summarize_jobs_to_dict(sa_session, jobs_source) -> Optional[JobsSummary]:
+def summarize_jobs_to_dict(sa_session, jobs_source) -> JobsSummary | None:
"""Produce a summary of jobs for job summary endpoints.
:type jobs_source: a Job or ImplicitCollectionJobs or None
@@ -1868,7 +1866,7 @@ def summarize_jobs_to_dict(sa_session, jobs_source) -> Optional[JobsSummary]:
:rtype: dict
:returns: dictionary containing job summary information
"""
- rval: Optional[JobsSummary] = None
+ rval: JobsSummary | None = None
if jobs_source is None:
pass
elif isinstance(jobs_source, model.Job):
@@ -2023,7 +2021,7 @@ def summarize_job_parameters(trans: ProvidesUserContext, job: Job) -> dict[str,
or input.type == "data_collection"
or isinstance(input_value, model.HistoryDatasetAssociation)
):
- value: list[Union[dict[str, Any], None]] = []
+ value: list[dict[str, Any] | None] = []
for element in listify(input_value):
if isinstance(element, model.HistoryDatasetAssociation):
hda = element
diff --git a/lib/galaxy/managers/landing.py b/lib/galaxy/managers/landing.py
index 9af245043b7..e0d1b8e99da 100644
--- a/lib/galaxy/managers/landing.py
+++ b/lib/galaxy/managers/landing.py
@@ -1,8 +1,4 @@
import logging
-from typing import (
- Optional,
- Union,
-)
from uuid import uuid4
from pydantic import (
@@ -70,7 +66,7 @@ from .tools import (
ToolRunReference,
)
-LandingRequestModel = Union[ToolLandingRequestModel, WorkflowLandingRequestModel]
+LandingRequestModel = ToolLandingRequestModel | WorkflowLandingRequestModel
FETCH_TOOL_ID = "__DATA_FETCH__"
@@ -78,7 +74,6 @@ log = logging.getLogger(__name__)
class LandingRequestManager:
-
def __init__(
self,
sa_session: galaxy_scoped_session,
@@ -86,7 +81,7 @@ class LandingRequestManager:
workflow_contents_manager: WorkflowContentsManager,
app: MinimalManagerApp,
config: GalaxyAppConfiguration,
- vault: Optional[Vault] = None,
+ vault: Vault | None = None,
):
self.sa_session = sa_session
self.security = security
@@ -120,7 +115,6 @@ class LandingRequestManager:
# Validate sample sheet metadata in request_state for __DATA_FETCH__ tool
if tool.id == "__DATA_FETCH__" and request_state:
-
# Check each item in request_state for sample sheet metadata
for item in landing_request_state.input_state.get("request_state", []):
# Try to parse as DataRequestCollectionUri to access sample sheet fields
@@ -193,7 +187,7 @@ class LandingRequestManager:
self._save(model)
return self._workflow_response(model)
- def validate_workflow_request_state(self, request_state: Optional[dict]) -> Optional[dict]:
+ def validate_workflow_request_state(self, request_state: dict | None) -> dict | None:
# This would ideally be run in the context of a workflow input definition
if isinstance(request_state, dict):
for key, value in request_state.items():
@@ -234,7 +228,7 @@ class LandingRequestManager:
return request_state
def claim_tool_landing_request(
- self, trans: ProvidesUserContext, uuid: UUID4, claim: Optional[ClaimLandingPayload]
+ self, trans: ProvidesUserContext, uuid: UUID4, claim: ClaimLandingPayload | None
) -> ToolLandingRequest:
request = self._get_tool_landing_request(uuid)
self._check_can_claim(trans, request, claim)
@@ -243,7 +237,7 @@ class LandingRequestManager:
return self._tool_response(request)
def claim_workflow_landing_request(
- self, trans: ProvidesUserContext, uuid: UUID4, claim: Optional[ClaimLandingPayload]
+ self, trans: ProvidesUserContext, uuid: UUID4, claim: ClaimLandingPayload | None
) -> WorkflowLandingRequest:
request = self._get_workflow_landing_request(uuid)
self._check_can_claim(trans, request, claim)
@@ -278,7 +272,7 @@ class LandingRequestManager:
return self._workflow_response(request)
def _check_can_claim(
- self, trans: ProvidesUserContext, request: LandingRequestModel, claim: Optional[ClaimLandingPayload]
+ self, trans: ProvidesUserContext, request: LandingRequestModel, claim: ClaimLandingPayload | None
):
if request.client_secret is not None:
if claim is None or not claim.client_secret:
@@ -331,7 +325,7 @@ class LandingRequestManager:
def _workflow_response(self, model: WorkflowLandingRequestModel) -> WorkflowLandingRequest:
- workflow_id: Optional[Union[int, str]] = None
+ workflow_id: int | str | None = None
if model.stored_workflow_id is not None:
workflow_id = model.stored_workflow_id
target_type = "stored_workflow"
@@ -369,7 +363,7 @@ class LandingRequestManager:
sa_session.add(model)
sa_session.commit()
- def _encrypt_headers_in_request_state(self, request_state: Optional[dict], landing_uuid: str) -> Optional[dict]:
+ def _encrypt_headers_in_request_state(self, request_state: dict | None, landing_uuid: str) -> dict | None:
if request_state is not None:
if has_sensitive_headers(request_state, self.url_headers_config):
if not self.vault:
@@ -386,7 +380,7 @@ class LandingRequestManager:
)
return request_state
- def _decrypt_headers_in_request_state(self, request_state: Optional[dict], landing_uuid: str):
+ def _decrypt_headers_in_request_state(self, request_state: dict | None, landing_uuid: str):
if request_state is not None and self.vault:
return decrypt_headers_in_data(
request_state,
diff --git a/lib/galaxy/managers/lddas.py b/lib/galaxy/managers/lddas.py
index 7e56010c31c..32e698ad4f9 100644
--- a/lib/galaxy/managers/lddas.py
+++ b/lib/galaxy/managers/lddas.py
@@ -1,7 +1,6 @@
import logging
from typing import (
Any,
- Optional,
)
from galaxy.managers import base as manager_base
@@ -33,7 +32,7 @@ class LDDAManager(DatasetAssociationManager[LibraryDatasetDatasetAssociation]):
trans, id, "LibraryDatasetDatasetAssociation", check_ownership=False, check_accessible=check_accessible
)
- def is_owner(self, item, user: Optional[User], **kwargs: Any) -> bool:
+ def is_owner(self, item, user: User | None, **kwargs: Any) -> bool:
"""
Return True if user owns the item.
"""
diff --git a/lib/galaxy/managers/libraries.py b/lib/galaxy/managers/libraries.py
index d1304551e44..584272dd494 100644
--- a/lib/galaxy/managers/libraries.py
+++ b/lib/galaxy/managers/libraries.py
@@ -3,9 +3,6 @@ Manager and Serializer for libraries.
"""
import logging
-from typing import (
- Optional,
-)
from sqlalchemy.exc import (
MultipleResultsFound,
@@ -68,7 +65,7 @@ class LibraryManager:
library = self.secure(trans, library, check_accessible)
return library
- def create(self, trans, name: str, description: Optional[str] = "", synopsis: Optional[str] = "") -> Library:
+ def create(self, trans, name: str, description: str | None = "", synopsis: str | None = "") -> Library:
"""
Create a new library.
"""
@@ -86,9 +83,9 @@ class LibraryManager:
self,
trans,
library: Library,
- name: Optional[str] = None,
- description: Optional[str] = None,
- synopsis: Optional[str] = None,
+ name: str | None = None,
+ description: str | None = None,
+ synopsis: str | None = None,
) -> Library:
"""
Update the given library
@@ -119,7 +116,7 @@ class LibraryManager:
trans.sa_session.commit()
return library
- def delete(self, trans, library: Library, undelete: Optional[bool] = False) -> Library:
+ def delete(self, trans, library: Library, undelete: bool | None = False) -> Library:
"""
Mark given library deleted/undeleted based on the flag.
"""
@@ -133,7 +130,7 @@ class LibraryManager:
trans.sa_session.commit()
return library
- def list(self, trans, deleted: Optional[bool] = False) -> tuple[Query, dict[str, set]]:
+ def list(self, trans, deleted: bool | None = False) -> tuple[Query, dict[str, set]]:
"""
Return a list of libraries from the DB.
@@ -215,7 +212,7 @@ class LibraryManager:
else:
return library
- def get_library_dict(self, trans, library: Library, prefetched_ids: Optional[dict[str, set]] = None) -> dict:
+ def get_library_dict(self, trans, library: Library, prefetched_ids: dict[str, set] | None = None) -> dict:
"""
Return library data in the form of a dictionary.
@@ -339,7 +336,7 @@ class LibraryManager:
return trans.app.security_agent.library_is_public(library)
-def get_containing_library_from_library_dataset(trans, library_dataset) -> Optional[Library]:
+def get_containing_library_from_library_dataset(trans, library_dataset) -> Library | None:
"""Given a library_dataset, get the containing library"""
folder = library_dataset.folder
while folder.parent:
diff --git a/lib/galaxy/managers/licenses.py b/lib/galaxy/managers/licenses.py
index b8bd2257e8b..3e95beff069 100644
--- a/lib/galaxy/managers/licenses.py
+++ b/lib/galaxy/managers/licenses.py
@@ -68,7 +68,7 @@ SPDX_LICENSES_STRING = resource_string(__name__, "licenses.json")
SPDX_LICENSES = json.loads(SPDX_LICENSES_STRING)
for license in SPDX_LICENSES["licenses"]:
license["recommended"] = license["licenseId"] in RECOMMENDED_LICENSES
- license["spdxUrl"] = f"https://spdx.org/licenses/{license['reference'][len('./'):]}"
+ license["spdxUrl"] = f"https://spdx.org/licenses/{license['reference'][len('./') :]}"
seeAlso = license.get("seeAlso", [])
if len(seeAlso) > 0:
url = seeAlso[0]
diff --git a/lib/galaxy/managers/markdown_parse.py b/lib/galaxy/managers/markdown_parse.py
index 5258a656552..bc1b004a99e 100644
--- a/lib/galaxy/managers/markdown_parse.py
+++ b/lib/galaxy/managers/markdown_parse.py
@@ -7,9 +7,6 @@ projects (e.g. gxformat2).
"""
import re
-from typing import (
- Union,
-)
BLOCK_FENCE_START = re.compile(r"```.*")
BLOCK_FENCE_END = re.compile(r"```[\s]*")
@@ -23,7 +20,7 @@ class DynamicArguments:
DYNAMIC_ARGUMENTS = DynamicArguments()
SHARED_ARGUMENTS: list[str] = ["collapse"]
-VALID_ARGUMENTS: dict[str, Union[list[str], DynamicArguments]] = {
+VALID_ARGUMENTS: dict[str, list[str] | DynamicArguments] = {
"generate_galaxy_version": [],
"generate_time": [],
"history_dataset_as_image": ["hid", "history_dataset_id", "input", "invocation_id", "output", "path"],
diff --git a/lib/galaxy/managers/markdown_util.py b/lib/galaxy/managers/markdown_util.py
index 257a5061d60..6c8c32de870 100644
--- a/lib/galaxy/managers/markdown_util.py
+++ b/lib/galaxy/managers/markdown_util.py
@@ -22,7 +22,6 @@ from datetime import datetime
from re import Match
from typing import (
Any,
- Optional,
)
import markdown
@@ -122,7 +121,7 @@ def ready_galaxy_markdown_for_import(trans, external_galaxy_markdown):
return (line, False)
def _remap_embed_container(match):
- object_id: Optional[str] = None
+ object_id: str | None = None
whole_match = match.group()
if id_match := re.search(ENCODED_ID_PATTERN, whole_match):
@@ -314,8 +313,8 @@ class GalaxyInternalMarkdownDirectiveHandler(metaclass=abc.ABCMeta):
def _remap_embed_container(match):
container = match.group("container")
- object_id: Optional[int] = None
- encoded_id: Optional[str] = None
+ object_id: int | None = None
+ encoded_id: str | None = None
if id_match := re.search(UNENCODED_ID_PATTERN, match.group()):
object_id = int(id_match.group(2))
@@ -380,7 +379,7 @@ class GalaxyInternalMarkdownDirectiveHandler(metaclass=abc.ABCMeta):
export_markdown_raw_embed = _remap_galaxy_markdown_calls(_remap_container, internal_galaxy_markdown)
def _remap_embed_container_ids(match):
- object_id: Optional[str] = None
+ object_id: str | None = None
whole_match = match.group()
if id_match := re.search(UNENCODED_ID_PATTERN, whole_match):
@@ -446,11 +445,11 @@ class GalaxyInternalMarkdownDirectiveHandler(metaclass=abc.ABCMeta):
pass
@abc.abstractmethod
- def handle_workflow_display(self, line, stored_workflow, workflow_version: Optional[int]):
+ def handle_workflow_display(self, line, stored_workflow, workflow_version: int | None):
pass
@abc.abstractmethod
- def handle_workflow_image(self, line, stored_workflow, workflow_version: Optional[int]):
+ def handle_workflow_image(self, line, stored_workflow, workflow_version: int | None):
pass
@abc.abstractmethod
@@ -563,10 +562,10 @@ class ReadyForExportMarkdownDirectiveHandler(GalaxyInternalMarkdownDirectiveHand
def handle_dataset_info(self, line, hda):
pass
- def handle_workflow_display(self, line, stored_workflow, workflow_version: Optional[int]):
+ def handle_workflow_display(self, line, stored_workflow, workflow_version: int | None):
pass
- def handle_workflow_image(self, line, stored_workflow, workflow_version: Optional[int]):
+ def handle_workflow_image(self, line, stored_workflow, workflow_version: int | None):
pass
def handle_workflow_license(self, line, stored_workflow):
@@ -761,7 +760,7 @@ class ToBasicMarkdownDirectiveHandler(GalaxyInternalMarkdownDirectiveHandler):
content = "*No Dataset Info Available*"
return (content, True)
- def handle_workflow_display(self, line, stored_workflow, workflow_version: Optional[int]):
+ def handle_workflow_display(self, line, stored_workflow, workflow_version: int | None):
# simple markdown
markdown = "---\n"
markdown += f"**Workflow:** {stored_workflow.name}\n\n"
@@ -781,7 +780,7 @@ class ToBasicMarkdownDirectiveHandler(GalaxyInternalMarkdownDirectiveHandler):
markdown = _workflow_license_as_simple_markdown(stored_workflow)
return (f"\n\n{markdown}\n\n", True)
- def handle_workflow_image(self, line, stored_workflow, workflow_version: Optional[int]):
+ def handle_workflow_image(self, line, stored_workflow, workflow_version: int | None):
workflow_manager = self.trans.app.workflow_manager
workflow = stored_workflow.get_internal_version(workflow_version)
image_data = workflow_manager.get_workflow_svg(self.trans, workflow, for_embed=True)
@@ -946,7 +945,7 @@ def to_html(basic_markdown: str) -> str:
return html
-def to_pdf_raw(basic_markdown: str, css_paths: Optional[list[str]] = None) -> bytes:
+def to_pdf_raw(basic_markdown: str, css_paths: list[str] | None = None) -> bytes:
"""Convert RAW markdown with specified CSS paths into bytes of a PDF."""
css_paths = css_paths or []
as_html = to_html(basic_markdown)
@@ -1186,8 +1185,8 @@ def resolve_invocation_markdown(trans, workflow_markdown):
if group:
return group
- target_match: Optional[Match]
- ref_object: Optional[Any]
+ target_match: Match | None
+ ref_object: Any | None
if output_match:
target_match = output_match
name = find_non_empty_group(target_match)
@@ -1229,9 +1228,6 @@ def resolve_invocation_markdown(trans, workflow_markdown):
if invocation is None:
return whole_match
- output_match = re.search(OUTPUT_LABEL_PATTERN, whole_match)
- input_match = re.search(INPUT_LABEL_PATTERN, whole_match)
-
def find_non_empty_group(match):
for group in match.groups():
if group:
@@ -1241,11 +1237,11 @@ def resolve_invocation_markdown(trans, workflow_markdown):
target_match = None
ref_object_type = None
- if output_match:
+ if output_match := re.search(OUTPUT_LABEL_PATTERN, whole_match):
target_match = output_match
name = find_non_empty_group(target_match)
ref_object = invocation.get_output_object(name)
- elif input_match:
+ elif input_match := re.search(INPUT_LABEL_PATTERN, whole_match):
target_match = input_match
name = find_non_empty_group(target_match)
ref_object = invocation.get_input_object(name)
@@ -1296,8 +1292,8 @@ def resolve_job_markdown(trans, job, job_markdown):
if group:
return group
- target_match: Optional[Match]
- ref_object: Optional[Any]
+ target_match: Match | None
+ ref_object: Any | None
if output_match := re.search(OUTPUT_LABEL_PATTERN, line):
target_match = output_match
name = find_non_empty_group(target_match)
@@ -1340,7 +1336,7 @@ def _workflow_license_as_simple_markdown(stored_workflow):
return markdown
-def _check_object(object_id: Optional[int], line: str) -> None:
+def _check_object(object_id: int | None, line: str) -> None:
if object_id is None:
raise MalformedContents(f"Missing object identifier [{line}].")
@@ -1349,7 +1345,7 @@ def _database_time_to_str(database_time: datetime) -> str:
return database_time.strftime("%Y-%m-%d, %H:%M:%S")
-def _link_to_markdown(url: Optional[str], title: Optional[str] = None):
+def _link_to_markdown(url: str | None, title: str | None = None):
if not url:
content = "*Link not configured, please contact Galaxy admin*"
return content
@@ -1406,7 +1402,7 @@ def _remap_galaxy_markdown_embedded_containers(func, markdown):
return new_markdown
-def _parse_directive_argument_value(arg_name: str, line: str) -> Optional[str]:
+def _parse_directive_argument_value(arg_name: str, line: str) -> str | None:
arg_pattern = re.compile(rf"{arg_name}=\s*{ARG_VAL_CAPTURED_REGEX}\s*")
match = re.search(arg_pattern, line)
if not match:
diff --git a/lib/galaxy/managers/model_stores.py b/lib/galaxy/managers/model_stores.py
index 0c111d822fc..492d9dcfd07 100644
--- a/lib/galaxy/managers/model_stores.py
+++ b/lib/galaxy/managers/model_stores.py
@@ -1,8 +1,3 @@
-from typing import (
- Optional,
- Union,
-)
-
from galaxy import model
from galaxy.exceptions import RequestParameterInvalidException
from galaxy.jobs.manager import JobManager
@@ -114,7 +109,7 @@ class ModelStoreManager:
include_deleted = request.include_deleted
export_metadata = self.set_history_export_request_metadata(request)
- exception_exporting_history: Optional[Exception] = None
+ exception_exporting_history: Exception | None = None
try:
with storage_context(
request.short_term_storage_request_id, self._short_term_storage_monitor
@@ -159,7 +154,7 @@ class ModelStoreManager:
export_files = "symlink" if request.include_files else None
export_metadata = self.set_invocation_export_request_metadata(request)
- exception_exporting_invocation: Optional[Exception] = None
+ exception_exporting_invocation: Exception | None = None
try:
with storage_context(
request.short_term_storage_request_id, self._short_term_storage_monitor
@@ -195,8 +190,8 @@ class ModelStoreManager:
user_context = self._build_user_context(request.user.user_id)
export_metadata = self.set_invocation_export_request_metadata(request)
- exception_exporting_invocation: Optional[Exception] = None
- uri: Optional[str] = None
+ exception_exporting_invocation: Exception | None = None
+ uri: str | None = None
try:
export_store = model.store.get_export_store_factory(
self._app,
@@ -263,8 +258,8 @@ class ModelStoreManager:
user_context = self._build_user_context(request.user.user_id)
export_metadata = self.set_history_export_request_metadata(request)
- exception_exporting_history: Optional[Exception] = None
- uri: Optional[str] = None
+ exception_exporting_history: Exception | None = None
+ uri: str | None = None
try:
export_store = model.store.get_export_store_factory(
self._app,
@@ -292,8 +287,8 @@ class ModelStoreManager:
)
def set_history_export_request_metadata(
- self, request: Union[WriteHistoryTo, GenerateHistoryDownload]
- ) -> Optional[ExportObjectMetadata]:
+ self, request: WriteHistoryTo | GenerateHistoryDownload
+ ) -> ExportObjectMetadata | None:
if request.export_association_id is None:
return None
request_dict = request.model_dump()
@@ -315,19 +310,19 @@ class ModelStoreManager:
def set_history_export_result_metadata(
self,
- export_association_id: Optional[int],
- export_metadata: Optional[ExportObjectMetadata],
+ export_association_id: int | None,
+ export_metadata: ExportObjectMetadata | None,
success: bool,
- uri: Optional[str] = None,
- error: Optional[str] = None,
+ uri: str | None = None,
+ error: str | None = None,
):
if export_association_id is not None and export_metadata is not None:
export_metadata.result_data = ExportObjectResultMetadata(success=success, uri=uri, error=error)
self._export_tracker.set_export_association_metadata(export_association_id, export_metadata)
def set_invocation_export_request_metadata(
- self, request: Union[WriteInvocationTo, GenerateInvocationDownload]
- ) -> Optional[ExportObjectMetadata]:
+ self, request: WriteInvocationTo | GenerateInvocationDownload
+ ) -> ExportObjectMetadata | None:
if request.export_association_id is None:
return None
request_dict = request.model_dump()
@@ -349,11 +344,11 @@ class ModelStoreManager:
def set_invocation_export_result_metadata(
self,
- export_association_id: Optional[int],
- export_metadata: Optional[ExportObjectMetadata],
+ export_association_id: int | None,
+ export_metadata: ExportObjectMetadata | None,
success: bool,
- uri: Optional[str] = None,
- error: Optional[str] = None,
+ uri: str | None = None,
+ error: str | None = None,
):
if export_association_id is not None and export_metadata is not None:
export_metadata.result_data = ExportObjectResultMetadata(success=success, uri=uri, error=error)
@@ -399,9 +394,9 @@ class ModelStoreManager:
def create_objects_from_store(
app: MinimalManagerApp,
- galaxy_user: Optional[model.User],
+ galaxy_user: model.User | None,
payload: StoreContentSource,
- history: Optional[model.History] = None,
+ history: model.History | None = None,
for_library: bool = False,
) -> ObjectImportTracker:
# Note: Galaxy's base Model uses use_enum_values=True, so enum fields
diff --git a/lib/galaxy/managers/notification.py b/lib/galaxy/managers/notification.py
index b7feebf179d..39e1d0ecbe3 100644
--- a/lib/galaxy/managers/notification.py
+++ b/lib/galaxy/managers/notification.py
@@ -5,8 +5,6 @@ from enum import Enum
from typing import (
cast,
NamedTuple,
- Optional,
- Union,
)
from urllib.parse import urlparse
@@ -113,7 +111,7 @@ class NotificationManager:
self,
sa_session: galaxy_scoped_session,
config: GalaxyAppConfiguration,
- sse_dispatcher: Optional[SSEEventDispatcher] = None,
+ sse_dispatcher: SSEEventDispatcher | None = None,
):
self.sa_session = sa_session
self.config = config
@@ -169,7 +167,7 @@ class NotificationManager:
def can_send_notifications_async(self):
return self.config.enable_celery_tasks
- def send_notification_to_recipients(self, request: NotificationCreateRequest) -> tuple[Optional[Notification], int]:
+ def send_notification_to_recipients(self, request: NotificationCreateRequest) -> tuple[Notification | None, int]:
"""
Creates a new notification and associates it with all the recipient users.
@@ -197,7 +195,7 @@ class NotificationManager:
run: DatasetStorageOperationRun,
execution_result: StorageOperationExecutionResult,
encode_id: Callable[[int], str],
- ) -> tuple[Optional[Notification], int]:
+ ) -> tuple[Notification | None, int]:
"""Create and send a storage operation notification to a single user."""
encoded_history_id = encode_id(run.history_id)
encoded_run_id = encode_id(run.id)
@@ -244,7 +242,7 @@ class NotificationManager:
def send_notification_internal(
self, request: NotificationCreateRequest, force_sync: bool = False
- ) -> Union[NotificationCreatedResponse, AsyncTaskResultSummary]:
+ ) -> NotificationCreatedResponse | AsyncTaskResultSummary:
"""Sends a notification to a list of recipients (users, groups or roles).
If `force_sync` is set to `True`, the notification recipients will be processed synchronously instead of
@@ -396,7 +394,7 @@ class NotificationManager:
self._notify_broadcast_via_sse(notification)
return notification
- def get_user_notification(self, user: User, notification_id: int, active_only: Optional[bool] = True):
+ def get_user_notification(self, user: User, notification_id: int, active_only: bool | None = True):
"""
Displays a notification belonging to the user.
"""
@@ -411,9 +409,9 @@ class NotificationManager:
def get_user_notifications(
self,
user: User,
- limit: Optional[int] = 50,
- offset: Optional[int] = None,
- since: Optional[datetime] = None,
+ limit: int | None = 50,
+ offset: int | None = None,
+ since: datetime | None = None,
):
"""
Displays the list of notifications belonging to the user.
@@ -450,7 +448,7 @@ class NotificationManager:
)
return self.sa_session.execute(stmt).scalar() or 0
- def get_broadcasted_notification(self, notification_id: int, active_only: Optional[bool] = True):
+ def get_broadcasted_notification(self, notification_id: int, active_only: bool | None = True):
stmt = (
select(*self.broadcast_notification_columns)
.select_from(Notification)
@@ -468,7 +466,7 @@ class NotificationManager:
raise ObjectNotFound
return result
- def get_all_broadcasted_notifications(self, since: Optional[datetime] = None, active_only: Optional[bool] = True):
+ def get_all_broadcasted_notifications(self, since: datetime | None = None, active_only: bool | None = True):
stmt = self._broadcasted_notifications_query(since, active_only)
result = self.sa_session.execute(stmt).fetchall()
return result
@@ -585,7 +583,7 @@ class NotificationManager:
return CleanupResultSummary(deleted_notifications_count, deleted_associations_count)
def _create_notification_model(
- self, payload: NotificationCreateData, galaxy_url: Optional[str] = None
+ self, payload: NotificationCreateData, galaxy_url: str | None = None
) -> Notification:
notification = Notification(
payload.source,
@@ -601,8 +599,8 @@ class NotificationManager:
def _user_notifications_query(
self,
user: User,
- since: Optional[datetime] = None,
- active_only: Optional[bool] = True,
+ since: datetime | None = None,
+ active_only: bool | None = True,
):
stmt = (
select(*self.user_notification_columns)
@@ -626,7 +624,7 @@ class NotificationManager:
return stmt
- def _broadcasted_notifications_query(self, since: Optional[datetime] = None, active_only: Optional[bool] = True):
+ def _broadcasted_notifications_query(self, since: datetime | None = None, active_only: bool | None = True):
stmt = (
select(*self.broadcast_notification_columns)
.select_from(Notification)
@@ -778,7 +776,7 @@ class NotificationContext(BaseModel):
variant: str
notification_settings_url: str
content: AnyNotificationContent
- galaxy_url: Optional[str] = None
+ galaxy_url: str | None = None
class EmailNotificationTemplateBuilder(Protocol):
@@ -858,9 +856,7 @@ class MessageEmailNotificationTemplateBuilder(EmailNotificationTemplateBuilder):
class NewSharedItemEmailNotificationTemplateBuilder(EmailNotificationTemplateBuilder):
def get_content(self, template_format: TemplateFormats) -> AnyNotificationContent:
- content = NewSharedItemNotificationContent.model_construct(
- **self.notification.content
- ) # type: ignore[arg-type]
+ content = NewSharedItemNotificationContent.model_construct(**self.notification.content) # type: ignore[arg-type]
return content
def get_subject(self) -> str:
@@ -869,7 +865,6 @@ class NewSharedItemEmailNotificationTemplateBuilder(EmailNotificationTemplateBui
class StorageOperationEmailNotificationTemplateBuilder(EmailNotificationTemplateBuilder):
-
markdown_to = {
TemplateFormats.HTML: to_html,
TemplateFormats.TXT: lambda x: x,
diff --git a/lib/galaxy/managers/object_store_instances.py b/lib/galaxy/managers/object_store_instances.py
index 899e1c4b15c..f4b7f0c68e0 100644
--- a/lib/galaxy/managers/object_store_instances.py
+++ b/lib/galaxy/managers/object_store_instances.py
@@ -8,10 +8,6 @@ To Test:
"""
import logging
-from typing import (
- Optional,
- Union,
-)
from uuid import uuid4
from pydantic import UUID4
@@ -88,7 +84,7 @@ class UserConcreteObjectStoreModel(ConcreteObjectStoreModel):
type: ObjectStoreTemplateType
template_id: str
template_version: int
- variables: Optional[dict[str, TemplateVariableValueType]]
+ variables: dict[str, TemplateVariableValueType] | None
secrets: list[str]
hidden: bool
active: bool
@@ -151,7 +147,7 @@ class ObjectStoreInstancesManager:
def _get_and_validate_target_upgrade_template(
self,
persisted_object_store: UserObjectStore,
- payload: Union[UpgradeInstancePayload, TestUpgradeInstancePayload],
+ payload: UpgradeInstancePayload | TestUpgradeInstancePayload,
) -> ObjectStoreTemplate:
template = self._get_template(persisted_object_store, payload.template_version)
validate_no_extra_variables_defined(payload.variables, template)
@@ -301,7 +297,7 @@ class ObjectStoreInstancesManager:
trans: ProvidesUserContext,
payload: CanTestPluginStatus,
template: ObjectStoreTemplate,
- ) -> tuple[Optional[ObjectStoreConfiguration], PluginAspectStatus]:
+ ) -> tuple[ObjectStoreConfiguration | None, PluginAspectStatus]:
template_parameters = prepare_template_parameters_for_testing(
trans, template, TemplateServerConfiguration(), payload, self._app_vault, self._app_config
)
@@ -316,7 +312,7 @@ class ObjectStoreInstancesManager:
def _connection_status(
self, trans: ProvidesUserContext, payload: CanTestPluginStatus, configuration: ObjectStoreConfiguration
- ) -> tuple[Optional[BaseObjectStore], PluginAspectStatus]:
+ ) -> tuple[BaseObjectStore | None, PluginAspectStatus]:
object_store = None
exception = None
try:
@@ -329,7 +325,7 @@ class ObjectStoreInstancesManager:
return UserObjectStore.__table__.c.uuid == uuid
def _get_template(
- self, persisted_object_store: UserObjectStore, template_version: Optional[int] = None
+ self, persisted_object_store: UserObjectStore, template_version: int | None = None
) -> ObjectStoreTemplate:
catalog = self._catalog
target_template_version = template_version or persisted_object_store.template_version
diff --git a/lib/galaxy/managers/pages.py b/lib/galaxy/managers/pages.py
index ec40c3836e3..1e76e6f10a7 100644
--- a/lib/galaxy/managers/pages.py
+++ b/lib/galaxy/managers/pages.py
@@ -12,9 +12,7 @@ from collections.abc import Callable
from html.entities import name2codepoint
from html.parser import HTMLParser
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
)
from sqlalchemy import (
@@ -144,7 +142,7 @@ class PageManager(sharable.SharableModelManager[model.Page], UsesAnnotations):
def index_query(
self, trans: ProvidesUserContext, payload: PageIndexQueryPayload, include_total_count: bool = False
- ) -> tuple["ScalarResult[model.Page]", Union[int, None]]:
+ ) -> tuple["ScalarResult[model.Page]", int | None]:
show_deleted = payload.deleted
show_own = payload.show_own
show_published = payload.show_published
@@ -739,7 +737,7 @@ def placeholderRenderForEdit(trans: ProvidesHistoryContext, item_class, item_id)
def placeholderRenderForSave(trans: ProvidesHistoryContext, item_class, item_id, encode=False):
encoded_item_id, decoded_item_id = get_page_identifiers(item_id, trans.app)
- item_name: Optional[str] = ""
+ item_name: str | None = ""
if item_class == "History":
history = trans.sa_session.get(History, decoded_item_id)
history = base.security_check(trans, history, False, True)
diff --git a/lib/galaxy/managers/queue_metrics.py b/lib/galaxy/managers/queue_metrics.py
index 2a8da81caf1..ed6b1f678e8 100644
--- a/lib/galaxy/managers/queue_metrics.py
+++ b/lib/galaxy/managers/queue_metrics.py
@@ -27,7 +27,6 @@ import logging
from collections import defaultdict
from collections.abc import Callable
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -55,7 +54,7 @@ log = logging.getLogger(__name__)
def emit_control_queue_depth(
statsd_client: "VanillaGalaxyStatsdClient",
- connection: "Optional[Connection]",
+ connection: "Connection | None",
application_stack: ApplicationStack,
) -> None:
"""Emit ``galaxy.control_queue.depth`` per active webapp/handler queue.
@@ -132,8 +131,8 @@ def _run(name: str, statsd_client: "VanillaGalaxyStatsdClient", fn: Callable[[],
def emit_queue_metrics(
- statsd_client: "Optional[VanillaGalaxyStatsdClient]",
- connection: "Optional[Connection]",
+ statsd_client: "VanillaGalaxyStatsdClient | None",
+ connection: "Connection | None",
application_stack: ApplicationStack,
model: GalaxyModelMapping,
) -> None:
diff --git a/lib/galaxy/managers/quotas.py b/lib/galaxy/managers/quotas.py
index 4ae4bc216ab..fa1e486d275 100644
--- a/lib/galaxy/managers/quotas.py
+++ b/lib/galaxy/managers/quotas.py
@@ -7,8 +7,6 @@ For more information about quotas: https://galaxyproject.org/admin/disk-quotas/
import logging
from typing import (
cast,
- Optional,
- Union,
)
from sqlalchemy import (
@@ -106,7 +104,7 @@ class QuotaManager:
return quota, message
- def _parse_amount(self, amount: str) -> Optional[Union[int, bool]]:
+ def _parse_amount(self, amount: str) -> int | bool | None:
if amount.lower() in ("unlimited", "none", "no limit"):
return None
try:
@@ -114,7 +112,7 @@ class QuotaManager:
except ValueError:
return False
- def rename_quota(self, quota: Quota, params) -> Optional[str]:
+ def rename_quota(self, quota: Quota, params) -> str | None:
stmt = select(Quota).where(and_(Quota.name == params.name, Quota.id != quota.id)).limit(1)
if not params.name:
raise ActionInputError("Enter a valid name.")
@@ -132,7 +130,7 @@ class QuotaManager:
else:
return None
- def manage_users_and_groups_for_quota(self, quota: Quota, params, decode_id=None) -> Optional[str]:
+ def manage_users_and_groups_for_quota(self, quota: Quota, params, decode_id=None) -> str | None:
if quota.default:
raise ActionInputError("Default quotas cannot be associated with specific users and groups.")
else:
@@ -158,7 +156,7 @@ class QuotaManager:
else:
return None
- def edit_quota(self, quota: Quota, params) -> Optional[str]:
+ def edit_quota(self, quota: Quota, params) -> str | None:
if params.amount.lower() in ("unlimited", "none", "no limit"):
new_amount = None
else:
@@ -184,7 +182,7 @@ class QuotaManager:
else:
return None
- def set_quota_default(self, quota: Quota, params) -> Optional[str]:
+ def set_quota_default(self, quota: Quota, params) -> str | None:
if params.default != "no" and params.default not in model.DefaultQuotaAssociation.types.__members__.values():
raise ActionInputError("Enter a valid default type.")
else:
@@ -199,7 +197,7 @@ class QuotaManager:
self.sa_session.commit()
return message
- def unset_quota_default(self, quota: Quota, params=None) -> Optional[str]:
+ def unset_quota_default(self, quota: Quota, params=None) -> str | None:
message = None
if quota.default:
message = f"Quota '{quota.name}' is no longer the default for {quota.default[0].type} users."
@@ -277,5 +275,5 @@ class QuotaManager:
message += ", ".join(names)
return message
- def get_quota(self, trans, id: int, deleted: Optional[bool] = None) -> model.Quota:
+ def get_quota(self, trans, id: int, deleted: bool | None = None) -> model.Quota:
return base.get_object(trans, id, "Quota", check_ownership=False, check_accessible=False, deleted=deleted)
diff --git a/lib/galaxy/managers/remote_files.py b/lib/galaxy/managers/remote_files.py
index f2c3bb3e88d..5cdb2d253b3 100644
--- a/lib/galaxy/managers/remote_files.py
+++ b/lib/galaxy/managers/remote_files.py
@@ -1,6 +1,5 @@
import hashlib
import logging
-from typing import Optional
from galaxy import exceptions
from galaxy.files import (
@@ -37,14 +36,14 @@ class RemoteFilesManager:
self,
user_ctx: ProvidesUserContext,
target: str,
- format: Optional[RemoteFilesFormat],
- recursive: Optional[bool],
- disable: Optional[RemoteFilesDisableMode],
- write_intent: Optional[bool] = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- query: Optional[str] = None,
- sort_by: Optional[str] = None,
+ format: RemoteFilesFormat | None,
+ recursive: bool | None,
+ disable: RemoteFilesDisableMode | None,
+ write_intent: bool | None = False,
+ limit: int | None = None,
+ offset: int | None = None,
+ query: str | None = None,
+ sort_by: str | None = None,
) -> tuple[AnyRemoteFilesListResponse, int]:
"""Returns a list of remote files and directories available to the user and the total count of them."""
@@ -141,9 +140,9 @@ class RemoteFilesManager:
def get_files_source_plugins(
self,
user_context: ProvidesUserContext,
- browsable_only: Optional[bool] = True,
- include_kind: Optional[set[PluginKind]] = None,
- exclude_kind: Optional[set[PluginKind]] = None,
+ browsable_only: bool | None = True,
+ include_kind: set[PluginKind] | None = None,
+ exclude_kind: set[PluginKind] | None = None,
):
"""Display plugin information for each of the gxfiles:// URI targets available."""
user_file_source_context = ProvidesFileSourcesUserContext(user_context)
diff --git a/lib/galaxy/managers/secured.py b/lib/galaxy/managers/secured.py
index bee37a76fb8..3451cc86faf 100644
--- a/lib/galaxy/managers/secured.py
+++ b/lib/galaxy/managers/secured.py
@@ -8,7 +8,6 @@ import abc
from typing import (
Any,
Generic,
- Optional,
TypeVar,
)
@@ -34,14 +33,14 @@ class AccessibleManagerMixin(Generic[U]):
def by_id(self, id: int) -> U: ...
# don't want to override by_id since consumers will also want to fetch w/o any security checks
- def is_accessible(self, item: U, user: Optional[model.User], **kwargs: Any) -> bool:
+ def is_accessible(self, item: U, user: model.User | None, **kwargs: Any) -> bool:
"""
Return True if the item accessible to user.
"""
# override in subclasses
raise exceptions.NotImplemented("Abstract interface Method")
- def get_accessible(self, id: int, user: Optional[model.User], **kwargs: Any) -> U:
+ def get_accessible(self, id: int, user: model.User | None, **kwargs: Any) -> U:
"""
Return the item with the given id if it's accessible to user,
otherwise raise an error.
@@ -51,7 +50,7 @@ class AccessibleManagerMixin(Generic[U]):
item = self.by_id(id)
return self.error_unless_accessible(item, user, **kwargs)
- def error_unless_accessible(self, item: U, user: Optional[model.User], **kwargs: Any) -> U:
+ def error_unless_accessible(self, item: U, user: model.User | None, **kwargs: Any) -> U:
"""
Raise an error if the item is NOT accessible to user, otherwise return the item.
@@ -78,14 +77,14 @@ class OwnableManagerMixin(Generic[U]):
@abc.abstractmethod
def by_id(self, id: int) -> U: ...
- def is_owner(self, item: U, user: Optional[model.User], **kwargs: Any) -> bool:
+ def is_owner(self, item: U, user: model.User | None, **kwargs: Any) -> bool:
"""
Return True if user owns the item.
"""
# override in subclasses
raise exceptions.NotImplemented("Abstract interface Method")
- def get_owned(self, id: int, user: Optional[model.User], **kwargs: Any) -> U:
+ def get_owned(self, id: int, user: model.User | None, **kwargs: Any) -> U:
"""
Return the item with the given id if owned by the user,
otherwise raise an error.
@@ -95,7 +94,7 @@ class OwnableManagerMixin(Generic[U]):
item = self.by_id(id)
return self.error_unless_owner(item, user, **kwargs)
- def error_unless_owner(self, item: U, user: Optional[model.User], **kwargs: Any) -> U:
+ def error_unless_owner(self, item: U, user: model.User | None, **kwargs: Any) -> U:
"""
Raise an error if the item is NOT owned by user, otherwise return the item.
@@ -105,7 +104,7 @@ class OwnableManagerMixin(Generic[U]):
return item
raise exceptions.ItemOwnershipException(f"{self.model_class.__name__} is not owned by user")
- def get_mutable(self, id: int, user: Optional[model.User], **kwargs: Any) -> U:
+ def get_mutable(self, id: int, user: model.User | None, **kwargs: Any) -> U:
"""
Return the item with the given id if the user can mutate it,
otherwise raise an error. The user must be the owner of the item.
diff --git a/lib/galaxy/managers/sharable.py b/lib/galaxy/managers/sharable.py
index a9f6625b32a..acf9fd48dca 100644
--- a/lib/galaxy/managers/sharable.py
+++ b/lib/galaxy/managers/sharable.py
@@ -13,7 +13,6 @@ A sharable Galaxy object:
import logging
from typing import (
Any,
- Optional,
TypeVar,
)
@@ -70,7 +69,7 @@ class SharableModelManager(
user_share_model: type[UserShareAssociation]
#: the single character abbreviation used in username_and_slug: e.g. 'h' for histories: u/user/h/slug
- SINGLE_CHAR_ABBR: Optional[str] = None
+ SINGLE_CHAR_ABBR: str | None = None
def __init__(self, app: MinimalManagerApp):
super().__init__(app)
@@ -89,7 +88,7 @@ class SharableModelManager(
return self.list(filters=filters, **kwargs)
# .... owned/accessible interfaces
- def is_owner(self, item: model.Base, user: Optional[User], **kwargs: Any) -> bool:
+ def is_owner(self, item: model.Base, user: User | None, **kwargs: Any) -> bool:
"""
Return true if this sharable belongs to `user` (or `user` is an admin).
"""
@@ -98,7 +97,7 @@ class SharableModelManager(
return True
return item.user == user # type: ignore[attr-defined]
- def is_accessible(self, item, user: Optional[User], **kwargs: Any) -> bool:
+ def is_accessible(self, item, user: User | None, **kwargs: Any) -> bool:
"""
If the item is importable, is owned by `user`, or (the valid) `user`
is in 'users shared with' list for the item: return True.
@@ -245,8 +244,8 @@ class SharableModelManager(
return list(self._apply_fn_limit_offset_gen(items, limit, offset))
def get_sharing_extra_information(
- self, trans, item, users: set[User], errors: set[str], option: Optional[SharingOptions] = None
- ) -> Optional[ShareWithExtra]:
+ self, trans, item, users: set[User], errors: set[str], option: SharingOptions | None = None
+ ) -> ShareWithExtra | None:
"""Returns optional extra information about the shareability of the given item.
This function should be overridden in the particular manager class that wants
@@ -356,7 +355,7 @@ class SharableModelSerializer(
ratable.RatableSerializerMixin,
):
# TODO: stub
- SINGLE_CHAR_ABBR: Optional[str] = None
+ SINGLE_CHAR_ABBR: str | None = None
def __init__(self, app, **kwargs):
super().__init__(app, **kwargs)
diff --git a/lib/galaxy/managers/sse.py b/lib/galaxy/managers/sse.py
index cc049390a28..cf878a65533 100644
--- a/lib/galaxy/managers/sse.py
+++ b/lib/galaxy/managers/sse.py
@@ -16,9 +16,6 @@ from collections.abc import (
)
from dataclasses import dataclass
from datetime import datetime
-from typing import (
- Optional,
-)
from galaxy.util import now
from galaxy.web.statsd_client import VanillaGalaxyStatsdClient
@@ -36,7 +33,7 @@ def make_event_id() -> str:
return now().isoformat()
-def parse_event_id(event_id: str) -> Optional[datetime]:
+def parse_event_id(event_id: str) -> datetime | None:
"""Inverse of :func:`make_event_id`. Returns ``None`` if unparseable."""
try:
return datetime.fromisoformat(event_id)
@@ -55,7 +52,7 @@ class SSEEvent:
event: str # e.g. "notification_update", "broadcast_update", "notification_status"
data: str # JSON payload
- id: Optional[str] = None # ISO timestamp, used by EventSource as Last-Event-ID on reconnect
+ id: str | None = None # ISO timestamp, used by EventSource as Last-Event-ID on reconnect
def to_wire(self) -> str:
"""Serialize this event to the SSE wire format (``event:…\\ndata:…\\n[id:…\\n]\\n``)."""
@@ -80,11 +77,11 @@ class SSEConnectionManager:
(typically the Kombu daemon thread via control task handlers).
"""
- def __init__(self, statsd_client: Optional[VanillaGalaxyStatsdClient] = None) -> None:
+ def __init__(self, statsd_client: VanillaGalaxyStatsdClient | None = None) -> None:
self._connections: dict[int, set[asyncio.Queue]] = defaultdict(set)
self._session_connections: dict[int, set[asyncio.Queue]] = defaultdict(set)
self._broadcast_connections: set[asyncio.Queue] = set()
- self._loop: Optional[asyncio.AbstractEventLoop] = None
+ self._loop: asyncio.AbstractEventLoop | None = None
self._statsd_client = statsd_client
# Viewer subscriptions for non-owned histories. Each worker keeps its
# own copy; the producer fans out subscribe/unsubscribe via Kombu so
@@ -100,7 +97,7 @@ class SSEConnectionManager:
# -- Called from ASYNC context (uvicorn event loop thread) --
- def connect(self, user_id: Optional[int], galaxy_session_id: Optional[int] = None) -> asyncio.Queue:
+ def connect(self, user_id: int | None, galaxy_session_id: int | None = None) -> asyncio.Queue:
"""Register a new SSE connection. Returns a queue to await events from.
Called from the SSE endpoint handler (async context). A ``ready`` event is
@@ -129,9 +126,9 @@ class SSEConnectionManager:
def disconnect(
self,
- user_id: Optional[int],
+ user_id: int | None,
queue: asyncio.Queue,
- galaxy_session_id: Optional[int] = None,
+ galaxy_session_id: int | None = None,
) -> None:
"""Unregister an SSE connection.
@@ -303,10 +300,10 @@ class SSEConnectionManager:
async def stream(
self,
is_disconnected: IsDisconnected,
- user_id: Optional[int],
- catch_up: Optional[SSEEvent] = None,
+ user_id: int | None,
+ catch_up: SSEEvent | None = None,
keepalive: float = 30.0,
- galaxy_session_id: Optional[int] = None,
+ galaxy_session_id: int | None = None,
) -> AsyncIterator[str]:
"""Yield SSE-framed strings for one connected client.
diff --git a/lib/galaxy/managers/sse_dispatch.py b/lib/galaxy/managers/sse_dispatch.py
index efa2372f438..65f2d6e1bcb 100644
--- a/lib/galaxy/managers/sse_dispatch.py
+++ b/lib/galaxy/managers/sse_dispatch.py
@@ -14,7 +14,6 @@ import time
from collections.abc import Callable
from typing import (
Any,
- Optional,
)
from cachetools import TTLCache
@@ -52,15 +51,15 @@ class SSEEventDispatcher:
def __init__(
self,
- queue_worker: Optional[GalaxyQueueWorker],
+ queue_worker: GalaxyQueueWorker | None,
application_stack: ApplicationStack,
- statsd_client: Optional[VanillaGalaxyStatsdClient] = None,
+ statsd_client: VanillaGalaxyStatsdClient | None = None,
clock: Callable[[], float] = time.monotonic,
# Factory return is typed ``Any`` so ``ControlTask`` itself and test-only
# duck-typed doubles (FakeControlTask/BoomControlTask/NoopControlTask)
# all satisfy the signature under mypy.
control_task_factory: Callable[[GalaxyQueueWorker], Any] = ControlTask,
- queues_provider: Optional[Callable[[], list[Queue]]] = None,
+ queues_provider: Callable[[], list[Queue]] | None = None,
) -> None:
self._queue_worker = queue_worker
self._application_stack = application_stack
@@ -115,7 +114,7 @@ class SSEEventDispatcher:
dt_ms = int((time.perf_counter() - start_time) * 1000)
self._statsd_client.timing("galaxy.sse.dispatch.latency_ms", dt_ms, tags={"task": task})
- def notify_users(self, user_ids: list[int], payload: str, event_id: Optional[str] = None) -> None:
+ def notify_users(self, user_ids: list[int], payload: str, event_id: str | None = None) -> None:
self._send(
"notify_users",
{
@@ -125,7 +124,7 @@ class SSEEventDispatcher:
},
)
- def notify_broadcast(self, payload: str, event_id: Optional[str] = None) -> None:
+ def notify_broadcast(self, payload: str, event_id: str | None = None) -> None:
self._send(
"notify_broadcast",
{
@@ -137,8 +136,8 @@ class SSEEventDispatcher:
def history_update(
self,
user_updates: dict[str, list[int]],
- event_id: Optional[str] = None,
- session_updates: Optional[dict[str, list[int]]] = None,
+ event_id: str | None = None,
+ session_updates: dict[str, list[int]] | None = None,
) -> None:
kwargs: dict[str, Any] = {
"user_updates": user_updates,
@@ -153,8 +152,8 @@ class SSEEventDispatcher:
def subscribe_history_viewer(
self,
history_id: str,
- user_id: Optional[int] = None,
- session_id: Optional[int] = None,
+ user_id: int | None = None,
+ session_id: int | None = None,
) -> None:
"""Broadcast a viewer-subscription record so every webapp worker can
push history_update events to a user/session watching a history they
@@ -173,8 +172,8 @@ class SSEEventDispatcher:
def unsubscribe_history_viewer(
self,
history_id: str,
- user_id: Optional[int] = None,
- session_id: Optional[int] = None,
+ user_id: int | None = None,
+ session_id: int | None = None,
) -> None:
kwargs: dict[str, Any] = {"history_id": history_id}
if user_id is not None:
@@ -183,7 +182,7 @@ class SSEEventDispatcher:
kwargs["session_id"] = session_id
self._send("unsubscribe_history_viewer", kwargs)
- def entry_point_update(self, user_id: int, event_id: Optional[str] = None) -> None:
+ def entry_point_update(self, user_id: int, event_id: str | None = None) -> None:
"""Fan out a wake-up ``entry_point_update`` event for one user.
The client always refetches the canonical entry-point list on receipt,
diff --git a/lib/galaxy/managers/taggable.py b/lib/galaxy/managers/taggable.py
index fae4b644018..c556e51af00 100644
--- a/lib/galaxy/managers/taggable.py
+++ b/lib/galaxy/managers/taggable.py
@@ -6,7 +6,6 @@ Mixins for Taggable model managers and serializers.
import logging
import re
-from typing import Optional
from sqlalchemy import (
func,
@@ -61,7 +60,7 @@ class TaggableDeserializerMixin:
self.deserializers["tags"] = self.deserialize_tags
def deserialize_tags(
- self, item, key, val, *, user: Optional[model.User] = None, trans: ProvidesUserContext, **context
+ self, item, key, val, *, user: model.User | None = None, trans: ProvidesUserContext, **context
):
"""
Make sure `val` is a valid list of tag strings and assign them.
diff --git a/lib/galaxy/managers/tags.py b/lib/galaxy/managers/tags.py
index 7f55b9e4073..e4ee5bc2339 100644
--- a/lib/galaxy/managers/tags.py
+++ b/lib/galaxy/managers/tags.py
@@ -1,5 +1,4 @@
from enum import Enum
-from typing import Optional
from pydantic import Field
@@ -33,7 +32,7 @@ class ItemTagsPayload(Model):
title="Item class",
description="The name of the class of the item that will be tagged.",
)
- item_tags: Optional[TagCollection] = Field(
+ item_tags: TagCollection | None = Field(
default=None,
title="Item tags",
description="The list of tags that will replace the current tags associated with the item.",
@@ -46,7 +45,7 @@ class TagsManager:
def update(self, trans: ProvidesUserContext, payload: ItemTagsPayload) -> None:
"""Apply a new set of tags to an item; previous tags are deleted."""
user = trans.user
- new_tags: Optional[str] = None
+ new_tags: str | None = None
if payload.item_tags:
new_tags = ",".join(payload.item_tags)
item = self._get_item(trans.tag_handler, payload)
diff --git a/lib/galaxy/managers/tool_data.py b/lib/galaxy/managers/tool_data.py
index 12884160f33..b46e522e886 100644
--- a/lib/galaxy/managers/tool_data.py
+++ b/lib/galaxy/managers/tool_data.py
@@ -2,7 +2,6 @@ from os.path import basename
from pathlib import Path
from typing import (
cast,
- Optional,
)
from galaxy import exceptions
@@ -86,7 +85,7 @@ class ToolDataManager:
raise exceptions.ObjectNotFound("No such path in data table field.")
return full_path.absolute()
- def delete(self, table_name: str, values: Optional[str] = None) -> ToolDataDetails:
+ def delete(self, table_name: str, values: str | None = None) -> ToolDataDetails:
"""Removes an item from a data table"""
data_table = self._tabular_data_table(table_name)
if not values:
diff --git a/lib/galaxy/managers/tool_source.py b/lib/galaxy/managers/tool_source.py
index c0b02233063..6e9aec1f641 100644
--- a/lib/galaxy/managers/tool_source.py
+++ b/lib/galaxy/managers/tool_source.py
@@ -18,7 +18,6 @@ import hashlib
import logging
from typing import (
Any,
- Optional,
)
from sqlalchemy import select
@@ -76,7 +75,7 @@ def tool_source_identity_hash(tool: Any) -> str:
return hashlib.sha256("\0".join(identity).encode("utf-8")).hexdigest()
-def _lookup(session: Session, content_hash: str, source_class: str, identity_hash: str) -> Optional[ToolSource]:
+def _lookup(session: Session, content_hash: str, source_class: str, identity_hash: str) -> ToolSource | None:
return session.scalars(
select(ToolSource)
.where(
diff --git a/lib/galaxy/managers/tools.py b/lib/galaxy/managers/tools.py
index 30f7a19524b..fcb1dc05d40 100644
--- a/lib/galaxy/managers/tools.py
+++ b/lib/galaxy/managers/tools.py
@@ -2,9 +2,7 @@ import logging
from typing import (
Any,
NamedTuple,
- Optional,
TYPE_CHECKING,
- Union,
)
from uuid import UUID
@@ -49,23 +47,23 @@ if TYPE_CHECKING:
from galaxy.managers.base import OrmFilterParsersType
-def tool_payload_to_tool(app, tool_dict: dict[str, Any]) -> Optional[Tool]:
+def tool_payload_to_tool(app, tool_dict: dict[str, Any]) -> Tool | None:
tool_source = YamlToolSource(tool_dict)
tool = create_tool_from_source(app, tool_source=tool_source, tool_dir=None)
return tool
class ToolRunReference(NamedTuple):
- tool_id: Optional[str]
- tool_uuid: Optional[str]
- tool_version: Optional[str]
+ tool_id: str | None
+ tool_uuid: str | None
+ tool_version: str | None
def get_tool_from_trans(trans: ProvidesUserContext, tool_ref: ToolRunReference) -> Tool:
return get_tool_from_toolbox(trans.app.toolbox, tool_ref, trans.user)
-def get_tool_from_toolbox(toolbox: AbstractToolBox, tool_ref: ToolRunReference, user: Optional[User]) -> Tool:
+def get_tool_from_toolbox(toolbox: AbstractToolBox, tool_ref: ToolRunReference, user: User | None) -> Tool:
tool = toolbox.get_tool(
tool_id=tool_ref.tool_id, tool_uuid=tool_ref.tool_uuid, tool_version=tool_ref.tool_version, user=user
)
@@ -84,13 +82,13 @@ class DynamicToolManager(ModelManager[DynamicTool]):
if not any(role.type == model.Role.types.USER_TOOL_EXECUTE and not role.deleted for role in user.all_roles()):
raise exceptions.InsufficientPermissionsException("User is not allowed to run unprivileged tools")
- def get_tool_by_id_or_uuid(self, id_or_uuid: Union[int, str]) -> Union[DynamicTool, None]:
+ def get_tool_by_id_or_uuid(self, id_or_uuid: int | str) -> DynamicTool | None:
if isinstance(id_or_uuid, int):
return self.get_tool_by_id(id_or_uuid)
else:
return self.get_tool_by_uuid(id_or_uuid)
- def get_tool_by_uuid(self, uuid: Optional[Union[UUID, str]]):
+ def get_tool_by_uuid(self, uuid: UUID | str | None):
self._validate_uuid(uuid)
stmt = select(DynamicTool).where(DynamicTool.uuid == uuid, DynamicTool.public == true())
return self.session().scalars(stmt).one_or_none()
@@ -99,13 +97,13 @@ class DynamicToolManager(ModelManager[DynamicTool]):
stmt = select(DynamicTool).where(DynamicTool.tool_id == tool_id, DynamicTool.public == true())
return self.session().scalars(stmt).one_or_none()
- def get_unprivileged_tool_by_uuid(self, user: model.User, uuid: Union[UUID, str]):
+ def get_unprivileged_tool_by_uuid(self, user: model.User, uuid: UUID | str):
self._validate_uuid(uuid)
stmt = self.owned_unprivileged_statement(user).where(DynamicTool.uuid == uuid)
return self.session().scalars(stmt).one_or_none()
@staticmethod
- def _validate_uuid(uuid: Optional[Union[UUID, str]]):
+ def _validate_uuid(uuid: UUID | str | None):
if uuid is not None and isinstance(uuid, str):
try:
UUID(uuid)
@@ -127,8 +125,8 @@ class DynamicToolManager(ModelManager[DynamicTool]):
)
uuid = model.get_uuid()
- tool_directory: Optional[str] = None
- tool_path: Optional[str] = None
+ tool_directory: str | None = None
+ tool_path: str | None = None
if tool_payload.src == "from_path":
tool_format, representation, _ = artifact_class(None, tool_payload.model_dump())
tool_directory = tool_payload.tool_directory
@@ -190,8 +188,7 @@ class DynamicToolManager(ModelManager[DynamicTool]):
"Set 'enable_beta_tool_formats' in Galaxy config to create dynamic tools."
)
self.ensure_can_use_unprivileged_tool(user)
- lint_errors = lint_user_tool_source(tool_payload.representation)
- if lint_errors:
+ if lint_errors := lint_user_tool_source(tool_payload.representation):
raise exceptions.RequestParameterInvalidException("Tool failed lint checks: " + "; ".join(lint_errors))
dynamic_tool = self.create(
tool_format=tool_payload.representation.class_,
diff --git a/lib/galaxy/managers/tours.py b/lib/galaxy/managers/tours.py
index 7a1593e15a7..3542fafca40 100644
--- a/lib/galaxy/managers/tours.py
+++ b/lib/galaxy/managers/tours.py
@@ -1,7 +1,6 @@
import os
from typing import (
Any,
- Optional,
)
from webob.compat import cgi_FieldStorage
@@ -57,13 +56,13 @@ class TourGenerator:
self._tool: Tool = self._get_and_ensure_tool(tool_id, tool_version)
self._use_datasets = True
self._data_inputs: dict[str, Any] = {}
- self._tour: Optional[TourDetails] = None
+ self._tour: TourDetails | None = None
self._hids: dict[str, Any] = {}
self._test: ToolTestDescription
self._upload_test_data(performs_upload=performs_upload)
self._generate_tour(performs_upload=performs_upload)
- def _get_and_ensure_tool(self, tool_id: str, tool_version: Optional[str]) -> Tool:
+ def _get_and_ensure_tool(self, tool_id: str, tool_version: str | None) -> Tool:
"""Get the tool and ensure it exists."""
tool = self._trans.app.toolbox.get_tool(tool_id, tool_version)
if not tool:
diff --git a/lib/galaxy/managers/users.py b/lib/galaxy/managers/users.py
index 6447a6c6985..62fff39ffb9 100644
--- a/lib/galaxy/managers/users.py
+++ b/lib/galaxy/managers/users.py
@@ -9,7 +9,6 @@ import string
import time
from typing import (
Any,
- Optional,
)
from markupsafe import escape
@@ -158,8 +157,7 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
Update a user's email address, keeping the private role in sync and honoring activation settings.
Raises RequestParameterInvalidException on validation errors.
"""
- message = validate_email(trans, new_email, user)
- if message:
+ if message := validate_email(trans, new_email, user):
raise exceptions.RequestParameterInvalidException(message)
if user.email == new_email:
return
@@ -183,8 +181,7 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
"""
Update a user's public name after validating it. Raises RequestParameterInvalidException on validation errors.
"""
- message = validate_publicname(trans, new_username, user)
- if message:
+ if message := validate_publicname(trans, new_username, user):
raise exceptions.RequestParameterInvalidException(message)
if user.username == new_username:
return
@@ -317,7 +314,7 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
if self.by_email(email, case_sensitive=False) is not None:
raise exceptions.Conflict("Email must be unique", email=email)
- def by_id(self, user_id: int) -> Optional[model.User]:
+ def by_id(self, user_id: int) -> model.User | None:
return self.app.model.session.get(self.model_class, user_id)
# ---- filters
@@ -366,7 +363,7 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
return util.safe_str_cmp(bootstrap_hash, provided_hash)
# ---- admin
- def is_admin(self, user: Optional[model.User], trans=None) -> bool:
+ def is_admin(self, user: model.User | None, trans=None) -> bool:
"""Return True if this user is an admin (or session is authenticated as admin).
Do not pass trans to simply check if an existing user object is an admin user,
@@ -398,7 +395,7 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
return user
# ---- anonymous
- def is_anonymous(self, user: Optional[model.User]) -> bool:
+ def is_anonymous(self, user: model.User | None) -> bool:
"""
Return True if `user` is anonymous.
"""
@@ -461,7 +458,7 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
return self.app.quota_agent.get_quota_nice_size(user, quota_source_label=quota_source_label)
return self.app.quota_agent.get_percent(user=user, quota_source_label=quota_source_label)
- def quota_bytes(self, user, quota_source_label: Optional[str] = None):
+ def quota_bytes(self, user, quota_source_label: str | None = None):
return self.app.quota_agent.get_quota(user=user, quota_source_label=quota_source_label)
def change_password(self, trans, password=None, confirm=None, token=None, id=None, current=None):
@@ -750,7 +747,7 @@ class UserSerializer(base.ModelSerializer, deletable.PurgableSerializerMixin):
)
return rval
- def serialize_disk_usage_for(self, user: model.User, label: Optional[str]) -> UserQuotaUsage:
+ def serialize_disk_usage_for(self, user: model.User, label: str | None) -> UserQuotaUsage:
usage = user.dictify_usage_for(label)
quota_source_label = usage.quota_source_label
quota_percent = self.user_manager.quota(user, quota_source_label=quota_source_label)
diff --git a/lib/galaxy/managers/visualizations.py b/lib/galaxy/managers/visualizations.py
index efd3f0e5560..4d6b033f8f6 100644
--- a/lib/galaxy/managers/visualizations.py
+++ b/lib/galaxy/managers/visualizations.py
@@ -8,7 +8,6 @@ reproduce a specific view in a Galaxy visualization.
import logging
from typing import (
TYPE_CHECKING,
- Union,
)
from sqlalchemy import (
@@ -78,7 +77,7 @@ class VisualizationManager(sharable.SharableModelManager[model.Visualization]):
def index_query(
self, trans: ProvidesUserContext, payload: VisualizationIndexQueryPayload, include_total_count: bool = False
- ) -> tuple["ScalarResult[model.Visualization]", Union[int, None]]:
+ ) -> tuple["ScalarResult[model.Visualization]", int | None]:
show_deleted = payload.deleted
show_own = payload.show_own
show_published = payload.show_published
diff --git a/lib/galaxy/managers/workflow_completion.py b/lib/galaxy/managers/workflow_completion.py
index b8b66148367..94d1905f8f2 100644
--- a/lib/galaxy/managers/workflow_completion.py
+++ b/lib/galaxy/managers/workflow_completion.py
@@ -8,7 +8,6 @@ This module provides the WorkflowCompletionManager class which handles:
"""
import logging
-from typing import Optional
from sqlalchemy import select
from sqlalchemy.orm.scoping import scoped_session
@@ -38,7 +37,7 @@ class WorkflowCompletionManager:
def sa_session(self) -> scoped_session:
return self.app.model.context
- def check_and_record_completion(self, invocation_id: int) -> Optional[WorkflowInvocationCompletion]:
+ def check_and_record_completion(self, invocation_id: int) -> WorkflowInvocationCompletion | None:
"""
Check if invocation is complete and record completion if so.
@@ -85,7 +84,7 @@ class WorkflowCompletionManager:
return completion
- def poll_pending_completions(self, limit: int = 100, handler: Optional[str] = None) -> list[int]:
+ def poll_pending_completions(self, limit: int = 100, handler: str | None = None) -> list[int]:
"""
Find invocations that are SCHEDULED but not yet recorded as complete.
@@ -114,7 +113,7 @@ class WorkflowCompletionManager:
session = self.sa_session
return list(session.execute(stmt).scalars())
- def get_completion(self, invocation_id: int) -> Optional[WorkflowInvocationCompletion]:
+ def get_completion(self, invocation_id: int) -> WorkflowInvocationCompletion | None:
"""
Get the completion record for an invocation.
@@ -153,8 +152,7 @@ class WorkflowCompletionManager:
if not completion:
return False
- hooks_executed = completion.hooks_executed or []
- if hook_name not in hooks_executed:
+ if hook_name not in (hooks_executed := completion.hooks_executed or []):
hooks_executed.append(hook_name)
completion.hooks_executed = hooks_executed
session.commit()
diff --git a/lib/galaxy/managers/workflow_extraction_naming.py b/lib/galaxy/managers/workflow_extraction_naming.py
index 676ff7c3107..0866cf0f78d 100644
--- a/lib/galaxy/managers/workflow_extraction_naming.py
+++ b/lib/galaxy/managers/workflow_extraction_naming.py
@@ -3,7 +3,6 @@
from dataclasses import dataclass
from typing import (
Literal,
- Optional,
)
from galaxy.managers.context import ProvidesHistoryContext
@@ -32,7 +31,7 @@ class SuggestedName:
def suggested_output_name(
trans: ProvidesHistoryContext, content_id: int, content_kind: OutputContentKind
-) -> Optional[SuggestedName]:
+) -> SuggestedName | None:
"""Return a best-effort workflow output label suggestion for an HDA/HDCA."""
if content_kind == "hda":
hda = trans.sa_session.get(HistoryDatasetAssociation, content_id)
@@ -45,9 +44,7 @@ def suggested_output_name(
return _suggested_hdca_output_name(trans, _original_hdca(hdca))
-def _suggested_hda_output_name(
- trans: ProvidesHistoryContext, hda: HistoryDatasetAssociation
-) -> Optional[SuggestedName]:
+def _suggested_hda_output_name(trans: ProvidesHistoryContext, hda: HistoryDatasetAssociation) -> SuggestedName | None:
assoc = next(
(assoc for assoc in hda.creating_job_associations if not _skip_output_assoc_name(assoc.name)),
None,
@@ -63,9 +60,9 @@ def _suggested_hda_output_name(
def _suggested_hdca_output_name(
trans: ProvidesHistoryContext, hdca: HistoryDatasetCollectionAssociation
-) -> Optional[SuggestedName]:
+) -> SuggestedName | None:
output_name = hdca.implicit_output_name
- job: Optional[Job] = None
+ job: Job | None = None
if output_name and hdca.implicit_collection_jobs is not None:
job = hdca.implicit_collection_jobs.representative_job
else:
@@ -91,7 +88,7 @@ def _suggested_hdca_output_name(
)
-def _tool_for_job(trans: ProvidesHistoryContext, job: Optional[Job]):
+def _tool_for_job(trans: ProvidesHistoryContext, job: Job | None):
if job is None:
return None
try:
@@ -100,7 +97,7 @@ def _tool_for_job(trans: ProvidesHistoryContext, job: Optional[Job]):
return None
-def _params_for_job(tool, job: Optional[Job]):
+def _params_for_job(tool, job: Job | None):
if tool is None or job is None:
return None
try:
@@ -111,12 +108,12 @@ def _params_for_job(tool, job: Optional[Job]):
def _apply_chain(
*,
- content_name: Optional[str],
- tool_output: Optional[ToolOutputBase],
- port_name: Optional[str],
- params: Optional[dict],
+ content_name: str | None,
+ tool_output: ToolOutputBase | None,
+ port_name: str | None,
+ params: dict | None,
tool,
-) -> Optional[SuggestedName]:
+) -> SuggestedName | None:
rendered_name = None
if tool is not None and tool_output is not None and params is not None:
rendered_name = get_output_name(tool=tool, output=tool_output, params=dict(params))
@@ -132,11 +129,11 @@ def _apply_chain(
return _content_name_from_string(content_name)
-def _content_name(content) -> Optional[SuggestedName]:
+def _content_name(content) -> SuggestedName | None:
return _content_name_from_string(getattr(content, "name", None))
-def _content_name_from_string(content_name: Optional[str]) -> Optional[SuggestedName]:
+def _content_name_from_string(content_name: str | None) -> SuggestedName | None:
if content_name:
return SuggestedName(content_name, "renamed")
return None
diff --git a/lib/galaxy/managers/workflows.py b/lib/galaxy/managers/workflows.py
index 733dfa91183..85e6d0ab48e 100644
--- a/lib/galaxy/managers/workflows.py
+++ b/lib/galaxy/managers/workflows.py
@@ -7,10 +7,8 @@ from typing import (
Any,
cast,
NamedTuple,
- Optional,
TYPE_CHECKING,
TypeAlias,
- Union,
)
import yaml
@@ -169,7 +167,7 @@ class WorkflowsManager(sharable.SharableModelManager[model.StoredWorkflow], dele
def index_query(
self, trans: ProvidesUserContext, payload: WorkflowIndexQueryPayload, include_total_count: bool = False
- ) -> tuple["ScalarResult[model.StoredWorkflow]", Optional[int]]:
+ ) -> tuple["ScalarResult[model.StoredWorkflow]", int | None]:
show_published = payload.show_published
show_hidden = payload.show_hidden
show_deleted = payload.show_deleted
@@ -573,7 +571,7 @@ class WorkflowsManager(sharable.SharableModelManager[model.StoredWorkflow], dele
return invocations, total_matches
-MissingToolsT = list[tuple[str, str, Optional[str], str]]
+MissingToolsT = list[tuple[str, str, str | None, str]]
class CreatedWorkflow(NamedTuple):
@@ -584,7 +582,7 @@ class CreatedWorkflow(NamedTuple):
class RefactorRequest(RefactorActions):
style: str = "export"
- version: Optional[int] = None
+ version: int | None = None
class WorkflowSerializer(sharable.SharableModelSerializer):
@@ -641,7 +639,6 @@ class RawWorkflowDescription:
class WorkflowContentsManager(UsesAnnotations):
-
def __init__(self, app: MinimalManagerApp, trs_proxy: TrsProxy):
self.app = app
self.trs_proxy = trs_proxy
@@ -1356,7 +1353,7 @@ class WorkflowContentsManager(UsesAnnotations):
def _workflow_to_dict_editor(
self,
trans,
- stored: Optional[StoredWorkflow],
+ stored: StoredWorkflow | None,
workflow: Workflow,
tooltip: bool = True,
is_subworkflow: bool = False,
@@ -2027,8 +2024,8 @@ class WorkflowContentsManager(UsesAnnotations):
self.add_item_annotation(sa_session, trans.get_user(), step, annotation)
# Stick this in the step temporarily
- DictConnection: TypeAlias = dict[str, Union[int, str]]
- temp_input_connections: dict[str, Union[list[DictConnection], DictConnection]] = step_dict.get(
+ DictConnection: TypeAlias = dict[str, int | str]
+ temp_input_connections: dict[str, list[DictConnection] | DictConnection] = step_dict.get(
"input_connections", {}
)
step.temp_input_connections = temp_input_connections # type: ignore[assignment]
@@ -2358,10 +2355,10 @@ class WorkflowContentsManager(UsesAnnotations):
def get_or_create_workflow_from_trs(
self,
trans: ProvidesUserContext,
- trs_url: Optional[str],
- trs_id: Optional[str] = None,
- trs_version: Optional[str] = None,
- trs_server: Optional[str] = None,
+ trs_url: str | None,
+ trs_id: str | None = None,
+ trs_version: str | None = None,
+ trs_server: str | None = None,
):
user_id = trans.user and trans.user.id
assert user_id, "Cannot create workflow for anonymous user"
@@ -2379,7 +2376,7 @@ class WorkflowContentsManager(UsesAnnotations):
return workflow
def create_workflow_from_trs_url(
- self, trans: ProvidesUserContext, trs_url: str, trs_server: Optional[str] = None
+ self, trans: ProvidesUserContext, trs_url: str, trs_server: str | None = None
) -> StoredWorkflow:
_, trs_tool_id, trs_version_id = self.trs_proxy.get_trs_id_and_version_from_trs_url(trs_url=trs_url)
data = self.trs_proxy.get_version_from_trs_url(trs_url)
@@ -2425,8 +2422,8 @@ class WorkflowContentsManager(UsesAnnotations):
return created_workflow.stored_workflow
def get_workflow_by_trs_id_and_version(
- self, trs_id: str, trs_version: str, user_id: Optional[int] = None
- ) -> Optional[model.StoredWorkflow]:
+ self, trs_id: str, trs_version: str, user_id: int | None = None
+ ) -> model.StoredWorkflow | None:
sa_session = self.app.model.session
stmnt = (
@@ -2469,7 +2466,7 @@ class WorkflowCreateOptions(WorkflowStateResolutionOptions):
publish: bool = False
# true or false, effectively defaults to ``publish`` if None/unset
- importable: Optional[bool] = None
+ importable: bool | None = None
# following are install options, only used if import_tools is true
install_repository_dependencies: bool = False
@@ -2478,14 +2475,14 @@ class WorkflowCreateOptions(WorkflowStateResolutionOptions):
new_tool_panel_section_label: str = ""
tool_panel_section_id: str = ""
tool_panel_section_mapping: dict = {}
- shed_tool_conf: Optional[str] = None
+ shed_tool_conf: str | None = None
# for workflows imported by archive source
- archive_source: Optional[str] = None
- trs_tool_id: Optional[str] = None
- trs_version_id: Optional[str] = None
- trs_server: Optional[str] = None
- trs_url: Optional[str] = None
+ archive_source: str | None = None
+ trs_tool_id: str | None = None
+ trs_version_id: str | None = None
+ trs_server: str | None = None
+ trs_url: str | None = None
@property
def is_importable(self):
diff --git a/lib/galaxy/metadata/__init__.py b/lib/galaxy/metadata/__init__.py
index db6dfdeb566..b9ca909713e 100644
--- a/lib/galaxy/metadata/__init__.py
+++ b/lib/galaxy/metadata/__init__.py
@@ -7,7 +7,6 @@ import shutil
from logging import getLogger
from typing import (
Any,
- Optional,
TYPE_CHECKING,
)
@@ -77,14 +76,14 @@ class MetadataCollectionStrategy(metaclass=abc.ABCMeta):
job_metadata=None,
provided_metadata_style=None,
compute_tmp_dir=None,
- compute_version_path: Optional[str] = None,
+ compute_version_path: str | None = None,
include_command=True,
max_metadata_value_size=0,
max_discovered_files=None,
validate_outputs: bool = False,
object_store_conf=None,
tool=None,
- job: Optional[galaxy.model.Job] = None,
+ job: galaxy.model.Job | None = None,
link_data_only: bool = False,
kwds=None,
):
@@ -156,14 +155,14 @@ class PortableDirectoryMetadataGenerator(MetadataCollectionStrategy):
job_metadata=None,
provided_metadata_style=None,
compute_tmp_dir=None,
- compute_version_path: Optional[str] = None,
+ compute_version_path: str | None = None,
include_command=True,
max_metadata_value_size=0,
max_discovered_files=None,
validate_outputs: bool = False,
object_store_conf=None,
tool=None,
- job: Optional[galaxy.model.Job] = None,
+ job: galaxy.model.Job | None = None,
link_data_only: bool = False,
kwds=None,
):
diff --git a/lib/galaxy/metadata/set_metadata.py b/lib/galaxy/metadata/set_metadata.py
index 92bc33b2299..39f28cde5c3 100644
--- a/lib/galaxy/metadata/set_metadata.py
+++ b/lib/galaxy/metadata/set_metadata.py
@@ -19,9 +19,6 @@ import sys
import traceback
from functools import partial
from pathlib import Path
-from typing import (
- Optional,
-)
try:
from pulsar.client.staging import COMMAND_VERSION_FILENAME
@@ -178,8 +175,8 @@ def get_object_store(tool_job_working_directory, object_store=None):
def set_metadata_portable(
tool_job_working_directory=None,
- object_store: Optional[ObjectStore] = None,
- extended_metadata_collection: Optional[bool] = None,
+ object_store: ObjectStore | None = None,
+ extended_metadata_collection: bool | None = None,
):
is_celery_task = tool_job_working_directory is not None
tool_job_working_directory = Path(tool_job_working_directory or os.path.abspath(os.getcwd()))
@@ -308,7 +305,7 @@ def set_metadata_portable(
assert isinstance(import_model_store.sa_session, SessionlessContext)
tool_script_file = tool_job_working_directory / "tool_script.sh"
- job: Optional[Job] = None
+ job: Job | None = None
if export_store:
job = next(iter(import_model_store.sa_session.objects[Job].values()))
diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py
index 6f92e199195..a0f2b404705 100644
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -273,11 +273,11 @@ class ConfigurationTemplateEnvironmentVariable(TypedDict):
variable: str
-CONFIGURATION_TEMPLATE_ENVIRONMENT_ENTRY = Union[
- ConfigurationTemplateEnvironmentSecret, ConfigurationTemplateEnvironmentVariable
-]
+CONFIGURATION_TEMPLATE_ENVIRONMENT_ENTRY = (
+ ConfigurationTemplateEnvironmentSecret | ConfigurationTemplateEnvironmentVariable
+)
CONFIGURATION_TEMPLATE_ENVIRONMENT = list[CONFIGURATION_TEMPLATE_ENVIRONMENT_ENTRY]
-CONFIGURATION_TEMPLATE_CONFIGURATION_VALUE_TYPE = Union[str, bool, int]
+CONFIGURATION_TEMPLATE_CONFIGURATION_VALUE_TYPE = str | bool | int
CONFIGURATION_TEMPLATE_CONFIGURATION_VARIABLES_TYPE = dict[str, CONFIGURATION_TEMPLATE_CONFIGURATION_VALUE_TYPE]
CONFIGURATION_TEMPLATE_CONFIGURATION_SECRET_NAMES_TYPE = list[str]
CONFIGURATION_TEMPLATE_DEFINITION_TYPE = dict[str, Any]
@@ -301,13 +301,13 @@ REQUESTED_TRANSFORM_ACTIONS = list[RequestedTransformAction]
mapper_registry = registry(
type_annotation_map={
- Optional[STR_TO_STR_DICT]: JSONType,
- Optional[TRANSFORM_ACTIONS]: MutableJSONType,
- Optional[REQUESTED_TRANSFORM_ACTIONS]: MutableJSONType,
- Optional[CONFIGURATION_TEMPLATE_CONFIGURATION_VARIABLES_TYPE]: JSONType,
- Optional[CONFIGURATION_TEMPLATE_CONFIGURATION_SECRET_NAMES_TYPE]: JSONType,
- Optional[CONFIGURATION_TEMPLATE_DEFINITION_TYPE]: JSONType,
- Optional[CONFIGURATION_TEMPLATE_ENVIRONMENT]: JSONType,
+ STR_TO_STR_DICT | None: JSONType,
+ TRANSFORM_ACTIONS | None: MutableJSONType,
+ REQUESTED_TRANSFORM_ACTIONS | None: MutableJSONType,
+ CONFIGURATION_TEMPLATE_CONFIGURATION_VARIABLES_TYPE | None: JSONType,
+ CONFIGURATION_TEMPLATE_CONFIGURATION_SECRET_NAMES_TYPE | None: JSONType,
+ CONFIGURATION_TEMPLATE_DEFINITION_TYPE | None: JSONType,
+ CONFIGURATION_TEMPLATE_ENVIRONMENT | None: JSONType,
},
)
@@ -341,7 +341,7 @@ else:
_HasTable = object
-def get_uuid(uuid: Optional[Union[UUID, str]] = None) -> UUID:
+def get_uuid(uuid: UUID | str | None = None) -> UUID:
if isinstance(uuid, UUID):
return uuid
if not uuid:
@@ -352,7 +352,7 @@ def get_uuid(uuid: Optional[Union[UUID, str]] = None) -> UUID:
def to_json(sa_session, column, keys: list[str]):
assert sa_session.bind
if sa_session.bind.dialect.name == "postgresql":
- cast: Union[ColumnElement[Any], Cast[Any]] = func.cast(func.convert_from(column, "UTF8"), JSONB)
+ cast: ColumnElement[Any] | Cast[Any] = func.cast(func.convert_from(column, "UTF8"), JSONB)
for key in keys:
cast = cast.__getitem__(key)
return cast.astext
@@ -458,10 +458,10 @@ class SerializationOptions:
def __init__(
self,
for_edit: bool,
- serialize_dataset_objects: Optional[bool] = None,
- serialize_files_handler: Optional[SerializeFilesHandler] = None,
- strip_metadata_files: Optional[bool] = None,
- ignore_errors: Optional[bool] = False,
+ serialize_dataset_objects: bool | None = None,
+ serialize_files_handler: SerializeFilesHandler | None = None,
+ strip_metadata_files: bool | None = None,
+ ignore_errors: bool | None = False,
) -> None:
self.for_edit = for_edit
if serialize_dataset_objects is None:
@@ -540,7 +540,7 @@ class HasName:
class UsesCreateAndUpdateTime:
- update_time: Mapped[Optional[datetime]]
+ update_time: Mapped[datetime | None]
@property
def seconds_since_updated(self):
@@ -561,11 +561,11 @@ class WorkerProcess(Base, UsesCreateAndUpdateTime):
__table_args__ = (UniqueConstraint("server_name", "hostname"),)
id: Mapped[int] = mapped_column(primary_key=True)
- server_name: Mapped[Optional[str]] = mapped_column(String(255), index=True)
- hostname: Mapped[Optional[str]] = mapped_column(String(255))
- pid: Mapped[Optional[int]]
- update_time: Mapped[Optional[datetime]] = mapped_column(default=now, onupdate=now)
- app_type: Mapped[Optional[str]]
+ server_name: Mapped[str | None] = mapped_column(String(255), index=True)
+ hostname: Mapped[str | None] = mapped_column(String(255))
+ pid: Mapped[int | None]
+ update_time: Mapped[datetime | None] = mapped_column(default=now, onupdate=now)
+ app_type: Mapped[str | None]
def cached_id(galaxy_model_object):
@@ -595,8 +595,8 @@ def cached_id(galaxy_model_object):
class JobLike:
- job_messages: Mapped[Optional[list[AnyJobMessage]]]
- tool_id: Union[str, None]
+ job_messages: Mapped[list[AnyJobMessage] | None]
+ tool_id: str | None
MAX_NUMERIC = 10 ** (JOB_METRIC_PRECISION - JOB_METRIC_SCALE) - 1
def _init_metrics(self):
@@ -637,7 +637,7 @@ class JobLike:
tool_stderr,
job_stdout=None,
job_stderr=None,
- job_messages: Optional[list[AnyJobMessage]] = None,
+ job_messages: list[AnyJobMessage] | None = None,
):
def shrink_and_unicodify(what, stream):
if stream and len(stream) > galaxy.util.DATABASE_MAX_STRING_SIZE:
@@ -663,7 +663,7 @@ class JobLike:
self.job_stderr = None
if job_messages is not None:
- self.job_messages = cast(Optional[list[AnyJobMessage]], job_messages)
+ self.job_messages = cast(list[AnyJobMessage] | None, job_messages)
def log_str(self) -> str:
extra = ""
@@ -825,14 +825,14 @@ def calculate_disk_usage_per_objectstore(sa_session, user_id: int):
# move these to galaxy.schema.schema once galaxy-data depends on
# galaxy-schema.
class UserQuotaBasicUsage(BaseModel):
- quota_source_label: Optional[str] = None
+ quota_source_label: str | None = None
total_disk_usage: float
class UserQuotaUsage(UserQuotaBasicUsage):
- quota_percent: Optional[float] = None
- quota_bytes: Optional[int] = None
- quota: Optional[str] = None
+ quota_percent: float | None = None
+ quota_bytes: int | None = None
+ quota: str | None = None
class UserObjectstoreUsage(BaseModel):
@@ -861,18 +861,18 @@ class User(Base, Dictifiable, RepresentById):
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
email: Mapped[str] = mapped_column(TrimmedString(255), index=True, unique=True)
- username: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True, unique=True)
+ username: Mapped[str | None] = mapped_column(TrimmedString(255), index=True, unique=True)
password: Mapped[str] = mapped_column(TrimmedString(255))
- last_password_change: Mapped[Optional[datetime]] = mapped_column(default=now)
- external: Mapped[Optional[bool]] = mapped_column(default=False)
- form_values_id: Mapped[Optional[int]] = mapped_column(ForeignKey("form_values.id"), index=True)
+ last_password_change: Mapped[datetime | None] = mapped_column(default=now)
+ external: Mapped[bool | None] = mapped_column(default=False)
+ form_values_id: Mapped[int | None] = mapped_column(ForeignKey("form_values.id"), index=True)
preferred_object_store_id: Mapped[str] = mapped_column(String(255), nullable=True)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- purged: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- disk_usage: Mapped[Optional[Decimal]] = mapped_column(Numeric(15, 0), index=True)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ purged: Mapped[bool | None] = mapped_column(index=True, default=False)
+ disk_usage: Mapped[Decimal | None] = mapped_column(Numeric(15, 0), index=True)
# Column("person_metadata", JSONType), # TODO: add persistent, configurable metadata rep for workflow creator
active: Mapped[bool] = mapped_column(index=True, default=True)
- activation_token: Mapped[Optional[str]] = mapped_column(TrimmedString(64), index=True)
+ activation_token: Mapped[str | None] = mapped_column(TrimmedString(64), index=True)
addresses: Mapped[list["UserAddress"]] = relationship(
back_populates="user", order_by=lambda: desc(UserAddress.update_time)
@@ -881,7 +881,8 @@ class User(Base, Dictifiable, RepresentById):
default_permissions: Mapped[list["DefaultUserPermissions"]] = relationship(back_populates="user")
groups: Mapped[list["UserGroupAssociation"]] = relationship(back_populates="user")
histories: Mapped[list["History"]] = relationship(
- back_populates="user", order_by=lambda: desc(History.update_time) # type: ignore[has-type]
+ back_populates="user",
+ order_by=lambda: desc(History.update_time), # type: ignore[has-type]
)
active_histories: Mapped[list["History"]] = relationship(
primaryjoin=(lambda: (History.user_id == User.id) & (not_(History.deleted)) & (not_(History.archived))),
@@ -898,9 +899,11 @@ class User(Base, Dictifiable, RepresentById):
social_auth: Mapped[list["UserAuthnzToken"]] = relationship(back_populates="user")
stored_workflow_menu_entries: Mapped[list["StoredWorkflowMenuEntry"]] = relationship(
primaryjoin=(
- lambda: (StoredWorkflowMenuEntry.user_id == User.id)
- & (StoredWorkflowMenuEntry.stored_workflow_id == StoredWorkflow.id)
- & not_(StoredWorkflow.deleted)
+ lambda: (
+ (StoredWorkflowMenuEntry.user_id == User.id)
+ & (StoredWorkflowMenuEntry.stored_workflow_id == StoredWorkflow.id)
+ & not_(StoredWorkflow.deleted)
+ )
),
back_populates="user",
cascade="all, delete-orphan",
@@ -1317,7 +1320,7 @@ ON CONFLICT
def dictify_usage(self, object_store=None) -> list[UserQuotaBasicUsage]:
"""Include object_store to include empty/unused usage info."""
- used_labels: set[Union[str, None]] = set()
+ used_labels: set[str | None] = set()
rval: list[UserQuotaBasicUsage] = [
UserQuotaBasicUsage(
quota_source_label=None,
@@ -1347,7 +1350,7 @@ ON CONFLICT
return rval
- def dictify_usage_for(self, quota_source_label: Optional[str]) -> UserQuotaBasicUsage:
+ def dictify_usage_for(self, quota_source_label: str | None) -> UserQuotaBasicUsage:
rval: UserQuotaBasicUsage
if quota_source_label is None:
rval = UserQuotaBasicUsage(
@@ -1369,7 +1372,7 @@ ON CONFLICT
return rval
- def quota_source_usage_for(self, quota_source_label: Optional[str]) -> Optional["UserQuotaSourceUsage"]:
+ def quota_source_usage_for(self, quota_source_label: str | None) -> Optional["UserQuotaSourceUsage"]:
for quota_source_usage in self.quota_source_usages:
if quota_source_usage.quota_source_label == quota_source_label:
return quota_source_usage
@@ -1386,8 +1389,8 @@ class PasswordResetToken(Base):
__tablename__ = "password_reset_token"
token: Mapped[str] = mapped_column(String(32), primary_key=True, unique=True, index=True)
- expiration_time: Mapped[Optional[datetime]]
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ expiration_time: Mapped[datetime | None]
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
user: Mapped[Optional["User"]] = relationship()
def __init__(self, user, token=None):
@@ -1404,12 +1407,12 @@ class ToolSource(Base, Dictifiable, RepresentById):
__table_args__ = (UniqueConstraint("hash", "source_class", "identity_hash"),)
id: Mapped[int] = mapped_column(primary_key=True)
- hash: Mapped[Optional[str]] = mapped_column(Unicode(255))
+ hash: Mapped[str | None] = mapped_column(Unicode(255))
source: Mapped[dict] = mapped_column(JSONType)
source_class: Mapped[str] = mapped_column(TrimmedString(255))
- tool_id: Mapped[Optional[str]] = mapped_column(String(255), index=True)
- tool_version: Mapped[Optional[str]] = mapped_column(String(255))
- dynamic_tool_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dynamic_tool.id"), index=True)
+ tool_id: Mapped[str | None] = mapped_column(String(255), index=True)
+ tool_version: Mapped[str | None] = mapped_column(String(255))
+ dynamic_tool_id: Mapped[int | None] = mapped_column(ForeignKey("dynamic_tool.id"), index=True)
identity_hash: Mapped[str] = mapped_column(String(255))
dynamic_tool: Mapped[Optional["DynamicTool"]] = relationship()
@@ -1437,11 +1440,11 @@ class ToolRequest(Base, Dictifiable, RepresentById):
tool_source_id: Mapped[int] = mapped_column(ForeignKey("tool_source.id"), index=True)
history_id: Mapped[int] = mapped_column(ForeignKey("history.id"), index=True, nullable=False)
request: Mapped[dict] = mapped_column(JSONType)
- state: Mapped[Optional[str]] = mapped_column(TrimmedString(32), index=True)
- state_message: Mapped[Optional[str]] = mapped_column(JSONType, index=True)
+ state: Mapped[str | None] = mapped_column(TrimmedString(32), index=True)
+ state_message: Mapped[str | None] = mapped_column(JSONType, index=True)
# Validity of ``request`` (``not_validated`` / ``validated`` /
# ``validation_failed``). Set whenever the payload is captured.
- request_state: Mapped[Optional[str]] = mapped_column(TrimmedString(32))
+ request_state: Mapped[str | None] = mapped_column(TrimmedString(32))
tool_source: Mapped["ToolSource"] = relationship()
history: Mapped[Optional["History"]] = relationship(back_populates="tool_requests")
@@ -1476,25 +1479,25 @@ class UserDynamicToolAssociation(Base, Dictifiable, RepresentById):
dynamic_tool_id: Mapped[int] = mapped_column(ForeignKey("dynamic_tool.id"), index=True)
user_id: Mapped[int] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- hidden: Mapped[Optional[bool]] = mapped_column(default=False)
- active: Mapped[Optional[bool]] = mapped_column(default=True)
+ hidden: Mapped[bool | None] = mapped_column(default=False)
+ active: Mapped[bool | None] = mapped_column(default=True)
class DynamicTool(Base, Dictifiable, RepresentById):
__tablename__ = "dynamic_tool"
id: Mapped[int] = mapped_column(primary_key=True)
- uuid: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType())
+ uuid: Mapped[UUID | str | None] = mapped_column(UUIDType())
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
- tool_id: Mapped[Optional[str]] = mapped_column(Unicode(255))
- tool_version: Mapped[Optional[str]] = mapped_column(Unicode(255))
- tool_format: Mapped[Optional[str]] = mapped_column(Unicode(255))
- tool_path: Mapped[Optional[str]] = mapped_column(Unicode(255))
- tool_directory: Mapped[Optional[str]] = mapped_column(Unicode(255))
- hidden: Mapped[Optional[bool]] = mapped_column(default=True)
- active: Mapped[Optional[bool]] = mapped_column(default=True)
- value: Mapped[Optional[dict[str, Any]]] = mapped_column(MutableJSONType)
+ tool_id: Mapped[str | None] = mapped_column(Unicode(255))
+ tool_version: Mapped[str | None] = mapped_column(Unicode(255))
+ tool_format: Mapped[str | None] = mapped_column(Unicode(255))
+ tool_path: Mapped[str | None] = mapped_column(Unicode(255))
+ tool_directory: Mapped[str | None] = mapped_column(Unicode(255))
+ hidden: Mapped[bool | None] = mapped_column(default=True)
+ active: Mapped[bool | None] = mapped_column(default=True)
+ value: Mapped[dict[str, Any] | None] = mapped_column(MutableJSONType)
public: Mapped[bool] = mapped_column(default=False, server_default=false())
dict_collection_visible_keys = (
@@ -1546,10 +1549,10 @@ class JobMetricText(BaseJobMetric, RepresentById):
__tablename__ = "job_metric_text"
id: Mapped[int] = mapped_column(primary_key=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- plugin: Mapped[Optional[str]] = mapped_column(Unicode(255))
- metric_name: Mapped[Optional[str]] = mapped_column(Unicode(255))
- metric_value: Mapped[Optional[str]] = mapped_column(Unicode(JOB_METRIC_MAX_LENGTH))
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ plugin: Mapped[str | None] = mapped_column(Unicode(255))
+ metric_name: Mapped[str | None] = mapped_column(Unicode(255))
+ metric_value: Mapped[str | None] = mapped_column(Unicode(JOB_METRIC_MAX_LENGTH))
def copy_to_job(self, job: "Job"):
job.text_metrics.append(
@@ -1565,10 +1568,10 @@ class JobMetricNumeric(BaseJobMetric, RepresentById):
__tablename__ = "job_metric_numeric"
id: Mapped[int] = mapped_column(primary_key=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- plugin: Mapped[Optional[str]] = mapped_column(Unicode(255))
- metric_name: Mapped[Optional[str]] = mapped_column(Unicode(255))
- metric_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(JOB_METRIC_PRECISION, JOB_METRIC_SCALE))
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ plugin: Mapped[str | None] = mapped_column(Unicode(255))
+ metric_name: Mapped[str | None] = mapped_column(Unicode(255))
+ metric_value: Mapped[Decimal | None] = mapped_column(Numeric(JOB_METRIC_PRECISION, JOB_METRIC_SCALE))
def copy_to_job(self, job: "Job"):
job.numeric_metrics.append(
@@ -1584,20 +1587,20 @@ class TaskMetricText(BaseJobMetric, RepresentById):
__tablename__ = "task_metric_text"
id: Mapped[int] = mapped_column(primary_key=True)
- task_id: Mapped[Optional[int]] = mapped_column(ForeignKey("task.id"), index=True)
- plugin: Mapped[Optional[str]] = mapped_column(Unicode(255))
- metric_name: Mapped[Optional[str]] = mapped_column(Unicode(255))
- metric_value: Mapped[Optional[str]] = mapped_column(Unicode(JOB_METRIC_MAX_LENGTH))
+ task_id: Mapped[int | None] = mapped_column(ForeignKey("task.id"), index=True)
+ plugin: Mapped[str | None] = mapped_column(Unicode(255))
+ metric_name: Mapped[str | None] = mapped_column(Unicode(255))
+ metric_value: Mapped[str | None] = mapped_column(Unicode(JOB_METRIC_MAX_LENGTH))
class TaskMetricNumeric(BaseJobMetric, RepresentById):
__tablename__ = "task_metric_numeric"
id: Mapped[int] = mapped_column(primary_key=True)
- task_id: Mapped[Optional[int]] = mapped_column(ForeignKey("task.id"), index=True)
- plugin: Mapped[Optional[str]] = mapped_column(Unicode(255))
- metric_name: Mapped[Optional[str]] = mapped_column(Unicode(255))
- metric_value: Mapped[Optional[Decimal]] = mapped_column(Numeric(JOB_METRIC_PRECISION, JOB_METRIC_SCALE))
+ task_id: Mapped[int | None] = mapped_column(ForeignKey("task.id"), index=True)
+ plugin: Mapped[str | None] = mapped_column(Unicode(255))
+ metric_name: Mapped[str | None] = mapped_column(Unicode(255))
+ metric_value: Mapped[Decimal | None] = mapped_column(Numeric(JOB_METRIC_PRECISION, JOB_METRIC_SCALE))
InpDataDictT = dict[str, Optional["DatasetInstance"]]
@@ -1629,39 +1632,39 @@ class Job(Base, JobLike, UsesCreateAndUpdateTime, Dictifiable, Serializable):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, index=True, nullable=True)
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)
- library_folder_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_folder.id"), index=True)
- tool_id: Mapped[Optional[str]] = mapped_column(String(255), index=True)
- tool_version: Mapped[Optional[str]] = mapped_column(TEXT, default="1.0.0")
- galaxy_version: Mapped[Optional[str]] = mapped_column(String(64), default=None)
- dynamic_tool_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dynamic_tool.id"), index=True)
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True)
+ library_folder_id: Mapped[int | None] = mapped_column(ForeignKey("library_folder.id"), index=True)
+ tool_id: Mapped[str | None] = mapped_column(String(255), index=True)
+ tool_version: Mapped[str | None] = mapped_column(TEXT, default="1.0.0")
+ galaxy_version: Mapped[str | None] = mapped_column(String(64), default=None)
+ dynamic_tool_id: Mapped[int | None] = mapped_column(ForeignKey("dynamic_tool.id"), index=True)
state: Mapped[str] = mapped_column(String(64), index=True, nullable=True)
- info: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- copied_from_job_id: Mapped[Optional[int]]
- command_line: Mapped[Optional[str]] = mapped_column(TEXT)
- dependencies: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
- job_messages: Mapped[Optional[list[AnyJobMessage]]] = mapped_column(MutableJSONType)
- param_filename: Mapped[Optional[str]] = mapped_column(String(1024))
- runner_name: Mapped[Optional[str]] = mapped_column(String(255))
- job_stdout: Mapped[Optional[str]] = mapped_column(TEXT)
- job_stderr: Mapped[Optional[str]] = mapped_column(TEXT)
- tool_stdout: Mapped[Optional[str]] = mapped_column(TEXT)
- tool_stderr: Mapped[Optional[str]] = mapped_column(TEXT)
- exit_code: Mapped[Optional[int]]
- traceback: Mapped[Optional[str]] = mapped_column(TEXT)
- session_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_session.id", ondelete="SET NULL"), index=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- job_runner_name: Mapped[Optional[str]] = mapped_column(String(255))
- job_runner_external_id: Mapped[Optional[str]] = mapped_column(String(255), index=True)
- destination_id: Mapped[Optional[str]] = mapped_column(String(255))
- destination_params: Mapped[Optional[dict[str, Any]]] = mapped_column(MutableJSONType)
- object_store_id: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- imported: Mapped[Optional[bool]] = mapped_column(default=False, index=True)
- handler: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- preferred_object_store_id: Mapped[Optional[str]] = mapped_column(String(255))
- object_store_id_overrides: Mapped[Optional[dict[str, Optional[str]]]] = mapped_column(JSONType)
- tool_request_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tool_request.id"), index=True)
- tool_state: Mapped[Optional[dict[str, Any]]] = mapped_column(JSON().with_variant(JSONB, "postgresql"))
+ info: Mapped[str | None] = mapped_column(TrimmedString(255))
+ copied_from_job_id: Mapped[int | None]
+ command_line: Mapped[str | None] = mapped_column(TEXT)
+ dependencies: Mapped[bytes | None] = mapped_column(MutableJSONType)
+ job_messages: Mapped[list[AnyJobMessage] | None] = mapped_column(MutableJSONType)
+ param_filename: Mapped[str | None] = mapped_column(String(1024))
+ runner_name: Mapped[str | None] = mapped_column(String(255))
+ job_stdout: Mapped[str | None] = mapped_column(TEXT)
+ job_stderr: Mapped[str | None] = mapped_column(TEXT)
+ tool_stdout: Mapped[str | None] = mapped_column(TEXT)
+ tool_stderr: Mapped[str | None] = mapped_column(TEXT)
+ exit_code: Mapped[int | None]
+ traceback: Mapped[str | None] = mapped_column(TEXT)
+ session_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_session.id", ondelete="SET NULL"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ job_runner_name: Mapped[str | None] = mapped_column(String(255))
+ job_runner_external_id: Mapped[str | None] = mapped_column(String(255), index=True)
+ destination_id: Mapped[str | None] = mapped_column(String(255))
+ destination_params: Mapped[dict[str, Any] | None] = mapped_column(MutableJSONType)
+ object_store_id: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ imported: Mapped[bool | None] = mapped_column(default=False, index=True)
+ handler: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ preferred_object_store_id: Mapped[str | None] = mapped_column(String(255))
+ object_store_id_overrides: Mapped[dict[str, str | None] | None] = mapped_column(JSONType)
+ tool_request_id: Mapped[int | None] = mapped_column(ForeignKey("tool_request.id"), index=True)
+ tool_state: Mapped[dict[str, Any] | None] = mapped_column(JSON().with_variant(JSONB, "postgresql"))
dynamic_tool: Mapped[Optional["DynamicTool"]] = relationship()
tool_request: Mapped[Optional["ToolRequest"]] = relationship(back_populates="jobs")
@@ -1887,12 +1890,12 @@ class Job(Base, JobLike, UsesCreateAndUpdateTime, Dictifiable, Serializable):
job.history.add_pending_items()
def io_dicts(self, exclude_implicit_outputs=False) -> IoDicts:
- inp_data: dict[str, Optional[DatasetInstance]] = {da.name: da.dataset for da in self.input_datasets}
+ inp_data: dict[str, DatasetInstance | None] = {da.name: da.dataset for da in self.input_datasets}
out_data: dict[str, DatasetInstance] = {da.name: da.dataset for da in self.output_datasets}
inp_data.update([(da.name, da.dataset) for da in self.input_library_datasets])
out_data.update([(da.name, da.dataset) for da in self.output_library_datasets])
- out_collections: dict[str, Union[DatasetCollectionInstance, DatasetCollection]]
+ out_collections: dict[str, DatasetCollectionInstance | DatasetCollection]
if not exclude_implicit_outputs:
out_collections = {
obj.name: obj.dataset_collection_instance for obj in self.output_dataset_collection_instances
@@ -2531,27 +2534,27 @@ class Task(Base, JobLike, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- execution_time: Mapped[Optional[datetime]]
- update_time: Mapped[Optional[datetime]] = mapped_column(default=now, onupdate=now)
- state: Mapped[Optional[str]] = mapped_column(String(64), index=True)
- command_line: Mapped[Optional[str]] = mapped_column(TEXT)
- param_filename: Mapped[Optional[str]] = mapped_column(String(1024))
- runner_name: Mapped[Optional[str]] = mapped_column(String(255))
- job_stdout: Mapped[Optional[str]] = mapped_column(
+ execution_time: Mapped[datetime | None]
+ update_time: Mapped[datetime | None] = mapped_column(default=now, onupdate=now)
+ state: Mapped[str | None] = mapped_column(String(64), index=True)
+ command_line: Mapped[str | None] = mapped_column(TEXT)
+ param_filename: Mapped[str | None] = mapped_column(String(1024))
+ runner_name: Mapped[str | None] = mapped_column(String(255))
+ job_stdout: Mapped[str | None] = mapped_column(
TEXT
) # job_stdout makes sense here because it is short for job script standard out
- job_stderr: Mapped[Optional[str]] = mapped_column(TEXT)
- tool_stdout: Mapped[Optional[str]] = mapped_column(TEXT)
- tool_stderr: Mapped[Optional[str]] = mapped_column(TEXT)
- exit_code: Mapped[Optional[int]]
- job_messages: Mapped[Optional[list[AnyJobMessage]]] = mapped_column(MutableJSONType)
- info: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- traceback: Mapped[Optional[str]] = mapped_column(TEXT)
+ job_stderr: Mapped[str | None] = mapped_column(TEXT)
+ tool_stdout: Mapped[str | None] = mapped_column(TEXT)
+ tool_stderr: Mapped[str | None] = mapped_column(TEXT)
+ exit_code: Mapped[int | None]
+ job_messages: Mapped[list[AnyJobMessage] | None] = mapped_column(MutableJSONType)
+ info: Mapped[str | None] = mapped_column(TrimmedString(255))
+ traceback: Mapped[str | None] = mapped_column(TEXT)
job_id: Mapped[int] = mapped_column(ForeignKey("job.id"), index=True)
- working_directory: Mapped[Optional[str]] = mapped_column(String(1024))
- task_runner_name: Mapped[Optional[str]] = mapped_column(String(255))
- task_runner_external_id: Mapped[Optional[str]] = mapped_column(String(255))
- prepare_input_files_cmd: Mapped[Optional[str]] = mapped_column(TEXT)
+ working_directory: Mapped[str | None] = mapped_column(String(1024))
+ task_runner_name: Mapped[str | None] = mapped_column(String(255))
+ task_runner_external_id: Mapped[str | None] = mapped_column(String(255))
+ prepare_input_files_cmd: Mapped[str | None] = mapped_column(TEXT)
job: Mapped["Job"] = relationship(back_populates="tasks")
text_metrics: Mapped[list["TaskMetricText"]] = relationship()
numeric_metrics: Mapped[list["TaskMetricNumeric"]] = relationship()
@@ -2698,9 +2701,9 @@ class JobParameter(Base, RepresentById):
__tablename__ = "job_parameter"
id: Mapped[int] = mapped_column(primary_key=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- name: Mapped[Optional[str]] = mapped_column(String(255))
- value: Mapped[Optional[str]] = mapped_column(TEXT)
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ name: Mapped[str | None] = mapped_column(String(255))
+ value: Mapped[str | None] = mapped_column(TEXT)
def __init__(self, name, value):
self.name = name
@@ -2715,12 +2718,12 @@ class JobToInputDatasetAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
job_id: Mapped[int] = mapped_column(ForeignKey("job.id"), index=True, nullable=True)
- dataset_id: Mapped[Optional[int]] = mapped_column(
+ dataset_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_association.id"), index=True, nullable=True
)
- dataset_version: Mapped[Optional[int]]
+ dataset_version: Mapped[int | None]
name: Mapped[str] = mapped_column(String(255), nullable=True)
- adapter: Mapped[Optional[dict[str, Any]]] = mapped_column(JSONType, nullable=True)
+ adapter: Mapped[dict[str, Any] | None] = mapped_column(JSONType, nullable=True)
dataset: Mapped[Optional["HistoryDatasetAssociation"]] = relationship(
lazy="joined", back_populates="dependent_jobs"
)
@@ -2765,7 +2768,7 @@ class JobToInputDatasetCollectionAssociation(Base, RepresentById):
ForeignKey("history_dataset_collection_association.id"), index=True, nullable=True
)
name: Mapped[str] = mapped_column(String(255), nullable=True)
- adapter: Mapped[Optional[dict[str, Any]]] = mapped_column(JSONType, nullable=True)
+ adapter: Mapped[dict[str, Any] | None] = mapped_column(JSONType, nullable=True)
dataset_collection: Mapped["HistoryDatasetCollectionAssociation"] = relationship(lazy="joined")
job: Mapped["Job"] = relationship(back_populates="input_dataset_collections")
@@ -2784,7 +2787,7 @@ class JobToInputDatasetCollectionElementAssociation(Base, RepresentById):
ForeignKey("dataset_collection_element.id"), index=True, nullable=True
)
name: Mapped[str] = mapped_column(Unicode(255), nullable=True)
- adapter: Mapped[Optional[dict[str, Any]]] = mapped_column(JSONType, nullable=True)
+ adapter: Mapped[dict[str, Any] | None] = mapped_column(JSONType, nullable=True)
dataset_collection_element: Mapped["DatasetCollectionElement"] = relationship(lazy="joined")
job: Mapped["Job"] = relationship(back_populates="input_dataset_collection_elements")
@@ -2878,9 +2881,9 @@ class JobStateHistory(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- state: Mapped[Optional[str]] = mapped_column(String(64), index=True)
- info: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ state: Mapped[str | None] = mapped_column(String(64), index=True)
+ info: Mapped[str | None] = mapped_column(TrimmedString(255))
def __init__(self, job):
self.job_id = job.id
@@ -2893,12 +2896,12 @@ class JobCredentialsContextAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
job_id: Mapped[int] = mapped_column(ForeignKey("job.id"), index=True)
- user_credentials_id: Mapped[Optional[int]] = mapped_column(
+ user_credentials_id: Mapped[int | None] = mapped_column(
ForeignKey("user_credentials.id", ondelete="SET NULL"), index=True, nullable=True
)
service_name: Mapped[str] = mapped_column(String(255))
service_version: Mapped[str] = mapped_column(String(255))
- selected_group_id: Mapped[Optional[int]] = mapped_column(
+ selected_group_id: Mapped[int | None] = mapped_column(
ForeignKey("credentials_group.id", ondelete="SET NULL"), index=True, nullable=True
)
selected_group_name: Mapped[str] = mapped_column(String(255))
@@ -2910,10 +2913,10 @@ class JobCredentialsContextAssociation(Base, RepresentById):
def __init__(
self,
job: "Job",
- user_credentials_id: Optional[int],
+ user_credentials_id: int | None,
service_name: str,
service_version: str,
- selected_group_id: Optional[int],
+ selected_group_id: int | None,
selected_group_name: str,
):
self.job = job
@@ -2928,18 +2931,20 @@ class ImplicitlyCreatedDatasetCollectionInput(Base, RepresentById):
__tablename__ = "implicitly_created_dataset_collection_inputs"
id: Mapped[int] = mapped_column(primary_key=True)
- dataset_collection_id: Mapped[Optional[int]] = mapped_column(
+ dataset_collection_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_collection_association.id"), index=True
)
- input_dataset_collection_id: Mapped[Optional[int]] = mapped_column(
+ input_dataset_collection_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_collection_association.id"), index=True
)
- name: Mapped[Optional[str]] = mapped_column(Unicode(255))
+ name: Mapped[str | None] = mapped_column(Unicode(255))
input_dataset_collection: Mapped[Optional["HistoryDatasetCollectionAssociation"]] = relationship(
primaryjoin=(
- lambda: HistoryDatasetCollectionAssociation.id
- == ImplicitlyCreatedDatasetCollectionInput.input_dataset_collection_id
+ lambda: (
+ HistoryDatasetCollectionAssociation.id
+ == ImplicitlyCreatedDatasetCollectionInput.input_dataset_collection_id
+ )
),
)
@@ -3045,10 +3050,10 @@ class PostJobAction(Base, RepresentById):
__tablename__ = "post_job_action"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"), index=True)
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"), index=True)
action_type: Mapped[str] = mapped_column(String(255))
- output_name: Mapped[Optional[str]] = mapped_column(String(255))
- _action_arguments: Mapped[Optional[dict[str, Any]]] = mapped_column("action_arguments", MutableJSONType)
+ output_name: Mapped[str | None] = mapped_column(String(255))
+ _action_arguments: Mapped[dict[str, Any] | None] = mapped_column("action_arguments", MutableJSONType)
workflow_step: Mapped[Optional["WorkflowStep"]] = relationship(
back_populates="post_job_actions",
primaryjoin=(lambda: WorkflowStep.id == PostJobAction.workflow_step_id),
@@ -3098,20 +3103,20 @@ class JobExternalOutputMetadata(Base, RepresentById):
__tablename__ = "job_external_output_metadata"
id: Mapped[int] = mapped_column(primary_key=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- history_dataset_association_id: Mapped[Optional[int]] = mapped_column(
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ history_dataset_association_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_association.id"), index=True
)
- library_dataset_dataset_association_id: Mapped[Optional[int]] = mapped_column(
+ library_dataset_dataset_association_id: Mapped[int | None] = mapped_column(
ForeignKey("library_dataset_dataset_association.id"), index=True
)
- is_valid: Mapped[Optional[bool]] = mapped_column(default=True)
- filename_in: Mapped[Optional[str]] = mapped_column(String(255))
- filename_out: Mapped[Optional[str]] = mapped_column(String(255))
- filename_results_code: Mapped[Optional[str]] = mapped_column(String(255))
- filename_kwds: Mapped[Optional[str]] = mapped_column(String(255))
- filename_override_metadata: Mapped[Optional[str]] = mapped_column(String(255))
- job_runner_external_pid: Mapped[Optional[str]] = mapped_column(String(255))
+ is_valid: Mapped[bool | None] = mapped_column(default=True)
+ filename_in: Mapped[str | None] = mapped_column(String(255))
+ filename_out: Mapped[str | None] = mapped_column(String(255))
+ filename_results_code: Mapped[str | None] = mapped_column(String(255))
+ filename_kwds: Mapped[str | None] = mapped_column(String(255))
+ filename_override_metadata: Mapped[str | None] = mapped_column(String(255))
+ job_runner_external_pid: Mapped[str | None] = mapped_column(String(255))
history_dataset_association: Mapped[Optional["HistoryDatasetAssociation"]] = relationship(lazy="joined")
library_dataset_dataset_association: Mapped[Optional["LibraryDatasetDatasetAssociation"]] = relationship(
lazy="joined"
@@ -3159,11 +3164,11 @@ class JobExportHistoryArchive(Base, RepresentById):
__tablename__ = "job_export_history_archive"
id: Mapped[int] = mapped_column(primary_key=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)
- dataset_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dataset.id"), index=True)
- compressed: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- history_attrs_filename: Mapped[Optional[str]] = mapped_column(TEXT)
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True)
+ dataset_id: Mapped[int | None] = mapped_column(ForeignKey("dataset.id"), index=True)
+ compressed: Mapped[bool | None] = mapped_column(index=True, default=False)
+ history_attrs_filename: Mapped[str | None] = mapped_column(TEXT)
job: Mapped[Optional["Job"]] = relationship()
dataset: Mapped[Optional["Dataset"]] = relationship()
history: Mapped[Optional["History"]] = relationship(back_populates="exports")
@@ -3246,9 +3251,9 @@ class JobImportHistoryArchive(Base, RepresentById):
__tablename__ = "job_import_history_archive"
id: Mapped[int] = mapped_column(primary_key=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)
- archive_dir: Mapped[Optional[str]] = mapped_column(TEXT)
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True)
+ archive_dir: Mapped[str | None] = mapped_column(TEXT)
job: Mapped[Optional["Job"]] = relationship()
history: Mapped[Optional["History"]] = relationship()
@@ -3258,11 +3263,11 @@ class StoreExportAssociation(Base, RepresentById):
__table_args__ = (Index("ix_store_export_object", "object_id", "object_type"),)
id: Mapped[int] = mapped_column(primary_key=True)
- task_uuid: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType(), index=True, unique=True)
+ task_uuid: Mapped[UUID | str | None] = mapped_column(UUIDType(), index=True, unique=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- object_type: Mapped[Optional[str]] = mapped_column(TrimmedString(32))
- object_id: Mapped[Optional[int]]
- export_metadata: Mapped[Optional[dict]] = mapped_column(JSONType)
+ object_type: Mapped[str | None] = mapped_column(TrimmedString(32))
+ object_id: Mapped[int | None]
+ export_metadata: Mapped[dict | None] = mapped_column(JSONType)
class JobContainerAssociation(Base, RepresentById):
@@ -3270,11 +3275,11 @@ class JobContainerAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
job_id: Mapped[int] = mapped_column(ForeignKey("job.id"), index=True, nullable=True)
- container_type: Mapped[Optional[str]] = mapped_column(TEXT)
- container_name: Mapped[Optional[str]] = mapped_column(TEXT)
- container_info: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
- created_time: Mapped[Optional[datetime]] = mapped_column(default=now)
- modified_time: Mapped[Optional[datetime]] = mapped_column(default=now, onupdate=now)
+ container_type: Mapped[str | None] = mapped_column(TEXT)
+ container_name: Mapped[str | None] = mapped_column(TEXT)
+ container_info: Mapped[bytes | None] = mapped_column(MutableJSONType)
+ created_time: Mapped[datetime | None] = mapped_column(default=now)
+ modified_time: Mapped[datetime | None] = mapped_column(default=now, onupdate=now)
job: Mapped["Job"] = relationship(back_populates="container")
def __init__(self, **kwd):
@@ -3288,23 +3293,23 @@ class InteractiveToolEntryPoint(Base, Dictifiable, RepresentById):
__tablename__ = "interactivetool_entry_point"
id: Mapped[int] = mapped_column(primary_key=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- name: Mapped[Optional[str]] = mapped_column(TEXT)
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ name: Mapped[str | None] = mapped_column(TEXT)
token: Mapped[str] = mapped_column(TEXT)
- tool_port: Mapped[Optional[int]]
- host: Mapped[Optional[str]] = mapped_column(TEXT)
- port: Mapped[Optional[int]]
- protocol: Mapped[Optional[str]] = mapped_column(TEXT)
- entry_url: Mapped[Optional[str]] = mapped_column(TEXT)
- requires_domain: Mapped[Optional[bool]] = mapped_column(default=True)
- requires_path_in_url: Mapped[Optional[bool]] = mapped_column(default=False)
- requires_path_in_header_named: Mapped[Optional[str]] = mapped_column(TEXT)
- info: Mapped[Optional[dict]] = mapped_column(MutableJSONType)
- configured: Mapped[Optional[bool]] = mapped_column(default=False)
- deleted: Mapped[Optional[bool]] = mapped_column(default=False)
- created_time: Mapped[Optional[datetime]] = mapped_column(default=now)
- modified_time: Mapped[Optional[datetime]] = mapped_column(default=now, onupdate=now)
- label: Mapped[Optional[str]] = mapped_column(TEXT)
+ tool_port: Mapped[int | None]
+ host: Mapped[str | None] = mapped_column(TEXT)
+ port: Mapped[int | None]
+ protocol: Mapped[str | None] = mapped_column(TEXT)
+ entry_url: Mapped[str | None] = mapped_column(TEXT)
+ requires_domain: Mapped[bool | None] = mapped_column(default=True)
+ requires_path_in_url: Mapped[bool | None] = mapped_column(default=False)
+ requires_path_in_header_named: Mapped[str | None] = mapped_column(TEXT)
+ info: Mapped[dict | None] = mapped_column(MutableJSONType)
+ configured: Mapped[bool | None] = mapped_column(default=False)
+ deleted: Mapped[bool | None] = mapped_column(default=False)
+ created_time: Mapped[datetime | None] = mapped_column(default=now)
+ modified_time: Mapped[datetime | None] = mapped_column(default=now, onupdate=now)
+ label: Mapped[str | None] = mapped_column(TEXT)
job: Mapped[Optional["Job"]] = relationship(back_populates="interactivetool_entry_points", uselist=False)
dict_collection_visible_keys = [
@@ -3334,7 +3339,7 @@ class InteractiveToolEntryPoint(Base, Dictifiable, RepresentById):
requires_path_in_url=False,
configured=False,
deleted=False,
- token: Union[str, None] = None,
+ token: str | None = None,
**kwd,
):
super().__init__(**kwd)
@@ -3364,26 +3369,25 @@ class GenomeIndexToolData(Base, RepresentById): # TODO: params arg is lost
__tablename__ = "genome_index_tool_data"
id: Mapped[int] = mapped_column(primary_key=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- dataset_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dataset.id"), index=True)
- fasta_path: Mapped[Optional[str]] = mapped_column(String(255))
- created_time: Mapped[Optional[datetime]] = mapped_column(default=now)
- modified_time: Mapped[Optional[datetime]] = mapped_column(default=now, onupdate=now)
- indexer: Mapped[Optional[str]] = mapped_column(String(64))
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ dataset_id: Mapped[int | None] = mapped_column(ForeignKey("dataset.id"), index=True)
+ fasta_path: Mapped[str | None] = mapped_column(String(255))
+ created_time: Mapped[datetime | None] = mapped_column(default=now)
+ modified_time: Mapped[datetime | None] = mapped_column(default=now, onupdate=now)
+ indexer: Mapped[str | None] = mapped_column(String(64))
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
job: Mapped[Optional["Job"]] = relationship()
dataset: Mapped[Optional["Dataset"]] = relationship()
user: Mapped[Optional["User"]] = relationship()
class ChatExchange(Base, RepresentById):
-
__tablename__ = "chat_exchange"
id: Mapped[int] = mapped_column(primary_key=True)
user_id: Mapped[int] = mapped_column(ForeignKey("galaxy_user.id"), index=True, nullable=False)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True, nullable=True)
- page_id: Mapped[Optional[int]] = mapped_column(ForeignKey("page.id"), index=True, nullable=True)
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True, nullable=True)
+ page_id: Mapped[int | None] = mapped_column(ForeignKey("page.id"), index=True, nullable=True)
user: Mapped["User"] = relationship(back_populates="chat_exchanges")
messages: Mapped[list["ChatExchangeMessage"]] = relationship(back_populates="chat_exchange")
@@ -3408,7 +3412,7 @@ class ChatExchangeMessage(Base, RepresentById):
chat_exchange_id: Mapped[int] = mapped_column(ForeignKey("chat_exchange.id"), index=True)
create_time: Mapped[datetime] = mapped_column(default=now)
message: Mapped[str] = mapped_column(Text)
- feedback: Mapped[Optional[int]] = mapped_column(Integer)
+ feedback: Mapped[int | None] = mapped_column(Integer)
chat_exchange: Mapped["ChatExchange"] = relationship("ChatExchange", back_populates="messages")
def __init__(self, message, feedback=None):
@@ -3422,8 +3426,8 @@ class Group(Base, Dictifiable, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- name: Mapped[Optional[str]] = mapped_column(String(255), index=True, unique=True)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ name: Mapped[str | None] = mapped_column(String(255), index=True, unique=True)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
quotas: Mapped[list["GroupQuotaAssociation"]] = relationship(back_populates="group")
roles: Mapped[list["GroupRoleAssociation"]] = relationship(back_populates="group")
users: Mapped[list["UserGroupAssociation"]] = relationship("UserGroupAssociation", back_populates="group")
@@ -3460,10 +3464,10 @@ class Notification(Base, Dictifiable, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- publication_time: Mapped[Optional[datetime]] = mapped_column(
+ publication_time: Mapped[datetime | None] = mapped_column(
default=now
) # The date of publication, can be a future date to allow scheduling
- expiration_time: Mapped[Optional[datetime]] = mapped_column(
+ expiration_time: Mapped[datetime | None] = mapped_column(
default=now() + timedelta(days=30 * 6)
) # The expiration date, expired notifications will be permanently removed from DB regularly
source: Mapped[str] = mapped_column(
@@ -3478,12 +3482,12 @@ class Notification(Base, Dictifiable, RepresentById):
dispatched: Mapped[bool] = mapped_column(
Boolean, index=True, default=False
) # Whether the notification has been dispatched to users via other channels
- galaxy_url: Mapped[Optional[str]] = mapped_column(
+ galaxy_url: Mapped[str | None] = mapped_column(
String(255)
) # The URL to the Galaxy instance, used for generating links in the notification
# A bug in early 23.1 led to values being stored as json string, so we use this special type to process the result value twice.
# content should always be a dict
- content: Mapped[Optional[bytes]] = mapped_column(DoubleEncodedJsonType)
+ content: Mapped[bytes | None] = mapped_column(DoubleEncodedJsonType)
user_notification_associations: Mapped[list["UserNotificationAssociation"]] = relationship(
back_populates="notification"
@@ -3502,9 +3506,9 @@ class UserNotificationAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
user_id: Mapped[int] = mapped_column(ForeignKey("galaxy_user.id"), index=True, nullable=True)
notification_id: Mapped[int] = mapped_column(ForeignKey("notification.id"), index=True, nullable=True)
- seen_time: Mapped[Optional[datetime]]
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- update_time: Mapped[Optional[datetime]] = mapped_column(default=now, onupdate=now)
+ seen_time: Mapped[datetime | None]
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ update_time: Mapped[datetime | None] = mapped_column(default=now, onupdate=now)
user: Mapped["User"] = relationship(back_populates="all_notifications")
notification: Mapped["Notification"] = relationship(back_populates="user_notification_associations")
@@ -3571,19 +3575,19 @@ class History(Base, HasTags, UsesAnnotations, HasName, Serializable, UsesCreateA
_update_time: Mapped[datetime] = mapped_column(
"update_time", DateTime, index=True, default=now, onupdate=now, nullable=True
)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- name: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- hid_counter: Mapped[Optional[int]] = mapped_column(default=1)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- purged: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- importing: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- genome_build: Mapped[Optional[str]] = mapped_column(TrimmedString(40))
- importable: Mapped[Optional[bool]] = mapped_column(default=False)
- slug: Mapped[Optional[str]] = mapped_column(TEXT)
- published: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- preferred_object_store_id: Mapped[Optional[str]] = mapped_column(String(255))
- archived: Mapped[Optional[bool]] = mapped_column(index=True, default=False, server_default=false())
- archive_export_id: Mapped[Optional[int]] = mapped_column(ForeignKey("store_export_association.id"), default=None)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ name: Mapped[str | None] = mapped_column(TrimmedString(255))
+ hid_counter: Mapped[int | None] = mapped_column(default=1)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ purged: Mapped[bool | None] = mapped_column(index=True, default=False)
+ importing: Mapped[bool | None] = mapped_column(index=True, default=False)
+ genome_build: Mapped[str | None] = mapped_column(TrimmedString(40))
+ importable: Mapped[bool | None] = mapped_column(default=False)
+ slug: Mapped[str | None] = mapped_column(TEXT)
+ published: Mapped[bool | None] = mapped_column(index=True, default=False)
+ preferred_object_store_id: Mapped[str | None] = mapped_column(String(255))
+ archived: Mapped[bool | None] = mapped_column(index=True, default=False, server_default=false())
+ archive_export_id: Mapped[int | None] = mapped_column(ForeignKey("store_export_association.id"), default=None)
datasets: Mapped[list["HistoryDatasetAssociation"]] = relationship(
primaryjoin=(lambda: HistoryDatasetAssociation.history_id == History.id),
@@ -3608,11 +3612,9 @@ class History(Base, HasTags, UsesAnnotations, HasName, Serializable, UsesCreateA
dataset_collections: Mapped[list["HistoryDatasetCollectionAssociation"]] = relationship(back_populates="history")
active_dataset_collections: Mapped[list["HistoryDatasetCollectionAssociation"]] = relationship(
primaryjoin=(
- lambda: (
- and_(
- HistoryDatasetCollectionAssociation.history_id == History.id,
- not_(HistoryDatasetCollectionAssociation.deleted),
- )
+ lambda: and_(
+ HistoryDatasetCollectionAssociation.history_id == History.id,
+ not_(HistoryDatasetCollectionAssociation.deleted),
)
),
order_by=lambda: asc(HistoryDatasetCollectionAssociation.hid),
@@ -4107,9 +4109,9 @@ class History(Base, HasTags, UsesAnnotations, HasName, Serializable, UsesCreateA
def paginated_active_visible_datasets(
self,
*,
- extensions: Optional[set[str]] = None,
- valid_states: Optional[tuple[str, ...]] = None,
- search: Optional[str] = None,
+ extensions: set[str] | None = None,
+ valid_states: tuple[str, ...] | None = None,
+ search: str | None = None,
offset: int = 0,
limit: int = 50,
) -> tuple[list["HistoryDatasetAssociation"], int]:
@@ -4214,7 +4216,7 @@ class History(Base, HasTags, UsesAnnotations, HasName, Serializable, UsesCreateA
self,
*,
visible_only: bool = True,
- search: Optional[str] = None,
+ search: str | None = None,
offset: int = 0,
limit: int = 50,
) -> tuple[list["HistoryDatasetCollectionAssociation"], int]:
@@ -4382,9 +4384,9 @@ class Role(Base, Dictifiable, RepresentById):
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
name: Mapped[str] = mapped_column(String(255), index=True)
- description: Mapped[Optional[str]] = mapped_column(TEXT)
- type: Mapped[Optional[str]] = mapped_column(String(40), index=True)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ description: Mapped[str | None] = mapped_column(TEXT)
+ type: Mapped[str | None] = mapped_column(String(40), index=True)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
dataset_actions: Mapped[list["DatasetPermissions"]] = relationship(back_populates="role")
groups: Mapped[list["GroupRoleAssociation"]] = relationship(back_populates="role")
users: Mapped[list["UserRoleAssociation"]] = relationship(back_populates="role")
@@ -4420,8 +4422,8 @@ class UserQuotaSourceUsage(Base, Dictifiable, RepresentById):
dict_element_visible_keys = ["disk_usage", "quota_source_label"]
id: Mapped[int] = mapped_column(primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- quota_source_label: Mapped[Optional[str]] = mapped_column(String(32), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ quota_source_label: Mapped[str | None] = mapped_column(String(32), index=True)
# user had an index on disk_usage - does that make any sense? -John
disk_usage: Mapped[Decimal] = mapped_column(Numeric(15, 0), default=0)
user: Mapped[Optional["User"]] = relationship(back_populates="quota_source_usages")
@@ -4472,12 +4474,12 @@ class Quota(Base, Dictifiable, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- name: Mapped[Optional[str]] = mapped_column(String(255), index=True, unique=True)
- description: Mapped[Optional[str]] = mapped_column(TEXT)
- bytes: Mapped[Optional[int]] = mapped_column(BigInteger)
- operation: Mapped[Optional[str]] = mapped_column(String(8))
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- quota_source_label: Mapped[Optional[str]] = mapped_column(String(32), default=None)
+ name: Mapped[str | None] = mapped_column(String(255), index=True, unique=True)
+ description: Mapped[str | None] = mapped_column(TEXT)
+ bytes: Mapped[int | None] = mapped_column(BigInteger)
+ operation: Mapped[str | None] = mapped_column(String(8))
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ quota_source_label: Mapped[str | None] = mapped_column(String(32), default=None)
default: Mapped[list["DefaultQuotaAssociation"]] = relationship("DefaultQuotaAssociation", back_populates="quota")
groups: Mapped[list["GroupQuotaAssociation"]] = relationship(back_populates="quota")
users: Mapped[list["UserQuotaAssociation"]] = relationship(back_populates="quota")
@@ -4534,7 +4536,7 @@ class DefaultQuotaAssociation(Base, Dictifiable, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- type: Mapped[Optional[str]] = mapped_column(String(32))
+ type: Mapped[str | None] = mapped_column(String(32))
quota_id: Mapped[int] = mapped_column(ForeignKey("quota.id"), index=True, nullable=True)
quota: Mapped["Quota"] = relationship(back_populates="default")
@@ -4557,9 +4559,9 @@ class DatasetPermissions(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- action: Mapped[Optional[str]] = mapped_column(TEXT)
- dataset_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dataset.id"), index=True)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
+ action: Mapped[str | None] = mapped_column(TEXT)
+ dataset_id: Mapped[int | None] = mapped_column(ForeignKey("dataset.id"), index=True)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
dataset: Mapped[Optional["Dataset"]] = relationship(back_populates="actions")
role: Mapped[Optional["Role"]] = relationship(back_populates="dataset_actions")
@@ -4579,9 +4581,9 @@ class LibraryPermissions(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- action: Mapped[Optional[str]] = mapped_column(TEXT)
- library_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library.id"), index=True)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
+ action: Mapped[str | None] = mapped_column(TEXT)
+ library_id: Mapped[int | None] = mapped_column(ForeignKey("library.id"), index=True)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
library: Mapped[Optional["Library"]] = relationship(back_populates="actions")
role: Mapped[Optional["Role"]] = relationship()
@@ -4601,9 +4603,9 @@ class LibraryFolderPermissions(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- action: Mapped[Optional[str]] = mapped_column(TEXT)
- library_folder_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_folder.id"), index=True)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
+ action: Mapped[str | None] = mapped_column(TEXT)
+ library_folder_id: Mapped[int | None] = mapped_column(ForeignKey("library_folder.id"), index=True)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
folder: Mapped[Optional["LibraryFolder"]] = relationship(back_populates="actions")
role: Mapped[Optional["Role"]] = relationship()
@@ -4623,9 +4625,9 @@ class LibraryDatasetPermissions(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- action: Mapped[Optional[str]] = mapped_column(TEXT)
- library_dataset_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_dataset.id"), index=True)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
+ action: Mapped[str | None] = mapped_column(TEXT)
+ library_dataset_id: Mapped[int | None] = mapped_column(ForeignKey("library_dataset.id"), index=True)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
library_dataset: Mapped[Optional["LibraryDataset"]] = relationship(back_populates="actions")
role: Mapped[Optional["Role"]] = relationship()
@@ -4645,11 +4647,11 @@ class LibraryDatasetDatasetAssociationPermissions(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- action: Mapped[Optional[str]] = mapped_column(TEXT)
+ action: Mapped[str | None] = mapped_column(TEXT)
library_dataset_dataset_association_id: Mapped[int] = mapped_column(
ForeignKey("library_dataset_dataset_association.id"), index=True, nullable=True
)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
library_dataset_dataset_association: Mapped["LibraryDatasetDatasetAssociation"] = relationship(
back_populates="actions"
)
@@ -4669,9 +4671,9 @@ class DefaultUserPermissions(Base, RepresentById):
__tablename__ = "default_user_permissions"
id: Mapped[int] = mapped_column(primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- action: Mapped[Optional[str]] = mapped_column(TEXT)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ action: Mapped[str | None] = mapped_column(TEXT)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
user: Mapped[Optional["User"]] = relationship(back_populates="default_permissions")
role: Mapped[Optional["Role"]] = relationship()
@@ -4686,9 +4688,9 @@ class DefaultHistoryPermissions(Base, RepresentById):
__tablename__ = "default_history_permissions"
id: Mapped[int] = mapped_column(primary_key=True)
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)
- action: Mapped[Optional[str]] = mapped_column(TEXT)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True)
+ action: Mapped[str | None] = mapped_column(TEXT)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
history: Mapped[Optional["History"]] = relationship(back_populates="default_permissions")
role: Mapped[Optional["Role"]] = relationship()
@@ -4714,20 +4716,20 @@ class Dataset(Base, StorableObject, Serializable):
__table_args__ = (UniqueConstraint("uuid", name="uq_uuid_column"),)
id: Mapped[int] = mapped_column(primary_key=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
- state: Mapped[Optional[str]] = mapped_column(TrimmedString(64), index=True)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- purged: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- purgable: Mapped[Optional[bool]] = mapped_column(default=True)
- object_store_id: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- external_filename: Mapped[Optional[str]] = mapped_column(TEXT)
- _extra_files_path: Mapped[Optional[str]] = mapped_column(TEXT)
- created_from_basename: Mapped[Optional[str]] = mapped_column(TEXT)
- file_size: Mapped[Optional[Decimal]] = mapped_column(Numeric(15, 0))
- total_size: Mapped[Optional[Decimal]] = mapped_column(Numeric(15, 0))
- uuid: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType(), unique=True)
+ state: Mapped[str | None] = mapped_column(TrimmedString(64), index=True)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ purged: Mapped[bool | None] = mapped_column(index=True, default=False)
+ purgable: Mapped[bool | None] = mapped_column(default=True)
+ object_store_id: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ external_filename: Mapped[str | None] = mapped_column(TEXT)
+ _extra_files_path: Mapped[str | None] = mapped_column(TEXT)
+ created_from_basename: Mapped[str | None] = mapped_column(TEXT)
+ file_size: Mapped[Decimal | None] = mapped_column(Numeric(15, 0))
+ total_size: Mapped[Decimal | None] = mapped_column(Numeric(15, 0))
+ uuid: Mapped[UUID | str | None] = mapped_column(UUIDType(), unique=True)
actions: Mapped[list["DatasetPermissions"]] = relationship(back_populates="dataset")
job: Mapped[Optional["Job"]] = relationship(primaryjoin=(lambda: Dataset.job_id == Job.id))
@@ -4956,7 +4958,7 @@ class Dataset(Base, StorableObject, Serializable):
@overload
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]:
+ def get_size(self, nice_size: bool = False, calculate_size: bool = True) -> int | str:
"""Returns the size of the data on disk"""
if self.file_size:
if nice_size:
@@ -5067,7 +5069,7 @@ class Dataset(Base, StorableObject, Serializable):
# serialize Dataset objects only for jobs that can actually modify these models.
assert serialization_options.serialize_dataset_objects
- def to_int(n) -> Optional[int]:
+ def to_int(n) -> int | None:
return int(n) if n is not None else None
rval = dict_for(
@@ -5273,13 +5275,13 @@ class DatasetSource(Base, Dictifiable, Serializable):
__tablename__ = "dataset_source"
id: Mapped[int] = mapped_column(primary_key=True)
- dataset_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dataset.id"), index=True)
- source_uri: Mapped[Optional[str]] = mapped_column(TEXT)
- extra_files_path: Mapped[Optional[str]] = mapped_column(TEXT)
+ dataset_id: Mapped[int | None] = mapped_column(ForeignKey("dataset.id"), index=True)
+ source_uri: Mapped[str | None] = mapped_column(TEXT)
+ extra_files_path: Mapped[str | None] = mapped_column(TEXT)
# actions actually applied to this source when creating the dataset.
- transform: Mapped[Optional[TRANSFORM_ACTIONS]] = mapped_column(MutableJSONType)
+ transform: Mapped[TRANSFORM_ACTIONS | None] = mapped_column(MutableJSONType)
# actions that may be applied to this source when creating the dataset
- requested_transform: Mapped[Optional[REQUESTED_TRANSFORM_ACTIONS]] = mapped_column(MutableJSONType)
+ requested_transform: Mapped[REQUESTED_TRANSFORM_ACTIONS | None] = mapped_column(MutableJSONType)
dataset: Mapped[Optional["Dataset"]] = relationship(back_populates="sources")
hashes: Mapped[list["DatasetSourceHash"]] = relationship(back_populates="source")
dict_collection_visible_keys = ["id", "source_uri", "extra_files_path", "transform"]
@@ -5313,7 +5315,7 @@ class DatasetSource(Base, Dictifiable, Serializable):
class HasHashFunctionName:
- hash_function: Mapped[Optional[str]]
+ hash_function: Mapped[str | None]
@property
def hash_func_name(self) -> HashFunctionNameEnum:
@@ -5326,9 +5328,9 @@ class DatasetSourceHash(Base, Serializable, HasHashFunctionName):
__tablename__ = "dataset_source_hash"
id: Mapped[int] = mapped_column(primary_key=True)
- dataset_source_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dataset_source.id"), index=True)
- hash_function: Mapped[Optional[str]] = mapped_column(TEXT)
- hash_value: Mapped[Optional[str]] = mapped_column(TEXT)
+ dataset_source_id: Mapped[int | None] = mapped_column(ForeignKey("dataset_source.id"), index=True)
+ hash_function: Mapped[str | None] = mapped_column(TEXT)
+ hash_value: Mapped[str | None] = mapped_column(TEXT)
source: Mapped[Optional["DatasetSource"]] = relationship(back_populates="hashes")
def _serialize(self, id_encoder, serialization_options):
@@ -5351,10 +5353,10 @@ class DatasetHash(Base, Dictifiable, Serializable, HasHashFunctionName):
__tablename__ = "dataset_hash"
id: Mapped[int] = mapped_column(primary_key=True)
- dataset_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dataset.id"), index=True)
- hash_function: Mapped[Optional[str]] = mapped_column(TEXT)
- hash_value: Mapped[Optional[str]] = mapped_column(TEXT)
- extra_files_path: Mapped[Optional[str]] = mapped_column(TEXT)
+ dataset_id: Mapped[int | None] = mapped_column(ForeignKey("dataset.id"), index=True)
+ hash_function: Mapped[str | None] = mapped_column(TEXT)
+ hash_value: Mapped[str | None] = mapped_column(TEXT)
+ extra_files_path: Mapped[str | None] = mapped_column(TEXT)
dataset: Mapped[Optional["Dataset"]] = relationship(back_populates="hashes")
dict_collection_visible_keys = ["id", "hash_function", "hash_value", "extra_files_path"]
dict_element_visible_keys = ["id", "hash_function", "hash_value", "extra_files_path"]
@@ -5383,7 +5385,7 @@ class DatasetHash(Base, Dictifiable, Serializable, HasHashFunctionName):
return HashFunctionNameEnum(self.hash_function)
-DescribesHash = Union[DatasetSourceHash, DatasetHash]
+DescribesHash = DatasetSourceHash | DatasetHash
def datatype_for_extension(extension, datatypes_registry=None) -> "Data":
@@ -5401,18 +5403,18 @@ 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]]
+ copied_from_history_dataset_association_id: Mapped[int | None]
+ name: Mapped[str | None]
+ purged: Mapped[bool | None]
visible: Mapped[bool]
deleted: Mapped[bool]
- dataset_id: Mapped[Optional[int]]
- _state: Mapped[Optional[str]]
+ dataset_id: Mapped[int | None]
+ _state: Mapped[str | None]
states = Dataset.states
conversion_messages = Dataset.conversion_messages
permitted_actions = Dataset.permitted_actions
- creating_job_associations: list[Union[JobToOutputDatasetCollectionAssociation, JobToOutputDatasetAssociation]]
- dataset: Mapped[Optional[Dataset]]
+ creating_job_associations: list[JobToOutputDatasetCollectionAssociation | JobToOutputDatasetAssociation]
+ dataset: Mapped[Dataset | None]
copied_from_history_dataset_association: Optional["HistoryDatasetAssociation"]
copied_from_library_dataset_dataset_association: Optional["LibraryDatasetDatasetAssociation"]
dependent_jobs: list[JobToInputLibraryDatasetAssociation]
@@ -5893,7 +5895,7 @@ class DatasetInstance(RepresentById, UsesCreateAndUpdateTime, _HasTable):
def find_conversion_destination(
self, accepted_formats: list[str], **kwd
- ) -> tuple[bool, Optional[str], Optional["DatasetInstance"]]:
+ ) -> tuple[bool, str | None, Optional["DatasetInstance"]]:
"""Returns ( target_ext, existing converted dataset )"""
return self.datatype.find_conversion_destination(self, accepted_formats, _get_datatypes_registry(), **kwd)
@@ -5974,7 +5976,7 @@ class DatasetInstance(RepresentById, UsesCreateAndUpdateTime, _HasTable):
return _source_dataset_chain(self, [])
@property
- def creating_job(self) -> Optional[Job]:
+ def creating_job(self) -> Job | None:
# TODO this should work with `return self.dataset.job` (revise failing unit tests)
creating_job_associations = None
if self.creating_job_associations:
@@ -6099,12 +6101,12 @@ class HistoryDatasetAssociation(DatasetInstance, HasTags, UsesAnnotations, HasNa
Resource class that creates a relation between a dataset and a user history.
"""
- history_id: Mapped[Optional[int]]
- dataset_id: Mapped[Optional[int]]
+ history_id: Mapped[int | None]
+ dataset_id: Mapped[int | None]
extension: Mapped[str]
- _metadata: Mapped[Optional[dict[str, Any]]]
- version: Mapped[Optional[int]]
- hid: Mapped[Optional[int]]
+ _metadata: Mapped[dict[str, Any] | None]
+ version: Mapped[int | None]
+ hid: Mapped[int | None]
hidden_beneath_collection_instance: Mapped[Optional["HistoryDatasetCollectionAssociation"]]
tags: Mapped[list["HistoryDatasetAssociationTagAssociation"]]
copied_to_history_dataset_associations: Mapped[list["HistoryDatasetAssociation"]]
@@ -6476,15 +6478,15 @@ class HistoryDatasetAssociationHistory(Base):
__tablename__ = "history_dataset_association_history"
id: Mapped[int] = mapped_column(primary_key=True)
- history_dataset_association_id: Mapped[Optional[int]] = mapped_column(
+ history_dataset_association_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_association.id"), index=True
)
- update_time: Mapped[Optional[datetime]] = mapped_column(default=now)
- version: Mapped[Optional[int]]
- name: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- extension: Mapped[Optional[str]] = mapped_column(TrimmedString(64))
+ update_time: Mapped[datetime | None] = mapped_column(default=now)
+ version: Mapped[int | None]
+ name: Mapped[str | None] = mapped_column(TrimmedString(255))
+ extension: Mapped[str | None] = mapped_column(TrimmedString(64))
_metadata = Column("metadata", MetadataType)
- extended_metadata_id: Mapped[Optional[int]] = mapped_column(ForeignKey("extended_metadata.id"), index=True)
+ extended_metadata_id: Mapped[int | None] = mapped_column(ForeignKey("extended_metadata.id"), index=True)
def __init__(
self,
@@ -6514,11 +6516,11 @@ class HistoryDatasetAssociationDisplayAtAuthorization(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
- history_dataset_association_id: Mapped[Optional[int]] = mapped_column(
+ history_dataset_association_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_association.id"), index=True
)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- site: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ site: Mapped[str | None] = mapped_column(TrimmedString(255))
history_dataset_association: Mapped[Optional["HistoryDatasetAssociation"]] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -6532,13 +6534,13 @@ class HistoryDatasetAssociationSubset(Base, RepresentById):
__tablename__ = "history_dataset_association_subset"
id: Mapped[int] = mapped_column(primary_key=True)
- history_dataset_association_id: Mapped[Optional[int]] = mapped_column(
+ history_dataset_association_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_association.id"), index=True
)
- history_dataset_association_subset_id: Mapped[Optional[int]] = mapped_column(
+ history_dataset_association_subset_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_association.id"), index=True
)
- location: Mapped[Optional[str]] = mapped_column(Unicode(255), index=True)
+ location: Mapped[str | None] = mapped_column(Unicode(255), index=True)
hda: Mapped[Optional["HistoryDatasetAssociation"]] = relationship(
primaryjoin=(
@@ -6547,8 +6549,9 @@ class HistoryDatasetAssociationSubset(Base, RepresentById):
)
subset: Mapped[Optional["HistoryDatasetAssociation"]] = relationship(
primaryjoin=(
- lambda: HistoryDatasetAssociationSubset.history_dataset_association_subset_id
- == HistoryDatasetAssociation.id
+ lambda: (
+ HistoryDatasetAssociationSubset.history_dataset_association_subset_id == HistoryDatasetAssociation.id
+ )
),
)
@@ -6562,14 +6565,14 @@ class Library(Base, Dictifiable, HasName, Serializable):
__tablename__ = "library"
id: Mapped[int] = mapped_column(primary_key=True)
- root_folder_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_folder.id"), index=True)
+ root_folder_id: Mapped[int | None] = mapped_column(ForeignKey("library_folder.id"), index=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- name: Mapped[Optional[str]] = mapped_column(String(255), index=True)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- purged: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- description: Mapped[Optional[str]] = mapped_column(TEXT)
- synopsis: Mapped[Optional[str]] = mapped_column(TEXT)
+ name: Mapped[str | None] = mapped_column(String(255), index=True)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ purged: Mapped[bool | None] = mapped_column(index=True, default=False)
+ description: Mapped[str | None] = mapped_column(TEXT)
+ synopsis: Mapped[str | None] = mapped_column(TEXT)
root_folder = relationship("LibraryFolder", back_populates="library_root")
actions: Mapped[list["LibraryPermissions"]] = relationship(back_populates="library")
@@ -6640,16 +6643,16 @@ class LibraryFolder(Base, Dictifiable, HasName, Serializable):
__table_args__ = (Index("ix_library_folder_name", "name", mysql_length=200),)
id: Mapped[int] = mapped_column(primary_key=True)
- parent_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_folder.id"), index=True)
+ parent_id: Mapped[int | None] = mapped_column(ForeignKey("library_folder.id"), index=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- name: Mapped[Optional[str]] = mapped_column(TEXT)
- description: Mapped[Optional[str]] = mapped_column(TEXT)
- order_id: Mapped[Optional[int]] # not currently being used, but for possible future use
+ name: Mapped[str | None] = mapped_column(TEXT)
+ description: Mapped[str | None] = mapped_column(TEXT)
+ order_id: Mapped[int | None] # not currently being used, but for possible future use
item_count: Mapped[int] = mapped_column(nullable=True)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- purged: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- genome_build: Mapped[Optional[str]] = mapped_column(TrimmedString(40))
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ purged: Mapped[bool | None] = mapped_column(index=True, default=False)
+ genome_build: Mapped[str | None] = mapped_column(TrimmedString(40))
folders: Mapped[list["LibraryFolder"]] = relationship(
primaryjoin=(lambda: LibraryFolder.id == LibraryFolder.parent_id),
@@ -6670,8 +6673,10 @@ class LibraryFolder(Base, Dictifiable, HasName, Serializable):
datasets: Mapped[list["LibraryDataset"]] = relationship(
primaryjoin=(
- lambda: LibraryDataset.folder_id == LibraryFolder.id
- and LibraryDataset.library_dataset_dataset_association_id.isnot(None)
+ lambda: (
+ LibraryDataset.folder_id == LibraryFolder.id
+ and LibraryDataset.library_dataset_dataset_association_id.isnot(None)
+ )
),
order_by=(lambda: asc(LibraryDataset._name)),
viewonly=True,
@@ -6778,23 +6783,23 @@ class LibraryDataset(Base, Serializable):
id: Mapped[int] = mapped_column(primary_key=True)
# current version of dataset, if null, there is not a current version selected
- library_dataset_dataset_association_id: Mapped[Optional[int]] = mapped_column(
+ library_dataset_dataset_association_id: Mapped[int | None] = mapped_column(
ForeignKey(
"library_dataset_dataset_association.id", use_alter=True, name="library_dataset_dataset_association_id_fk"
),
index=True,
)
- folder_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_folder.id"), index=True)
+ folder_id: Mapped[int | None] = mapped_column(ForeignKey("library_folder.id"), index=True)
# not currently being used, but for possible future use
- order_id: Mapped[Optional[int]]
+ order_id: Mapped[int | None]
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
# when not None/null this will supercede display in library (but not when imported into user's history?)
- _name: Mapped[Optional[str]] = mapped_column("name", TrimmedString(255), index=True)
+ _name: Mapped[str | None] = mapped_column("name", TrimmedString(255), index=True)
# when not None/null this will supercede display in library (but not when imported into user's history?)
- _info: Mapped[Optional[str]] = mapped_column("info", TrimmedString(255))
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- purged: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ _info: Mapped[str | None] = mapped_column("info", TrimmedString(255))
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ purged: Mapped[bool | None] = mapped_column(index=True, default=False)
folder: Mapped[Optional["LibraryFolder"]] = relationship()
library_dataset_dataset_association = relationship(
"LibraryDatasetDatasetAssociation", foreign_keys=library_dataset_dataset_association_id, post_update=True
@@ -6898,7 +6903,7 @@ class LibraryDataset(Base, Serializable):
class LibraryDatasetDatasetAssociation(DatasetInstance, HasName, Serializable):
- message: Mapped[Optional[str]]
+ message: Mapped[str | None]
tags: Mapped[list["LibraryDatasetDatasetAssociationTagAssociation"]]
def __init__(
@@ -7082,7 +7087,7 @@ class ExtendedMetadata(Base, RepresentById):
__tablename__ = "extended_metadata"
id: Mapped[int] = mapped_column(primary_key=True)
- data: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
+ data: Mapped[bytes | None] = mapped_column(MutableJSONType)
children: Mapped[list["ExtendedMetadataIndex"]] = relationship(back_populates="extended_metadata")
def __init__(self, data):
@@ -7093,11 +7098,11 @@ class ExtendedMetadataIndex(Base, RepresentById):
__tablename__ = "extended_metadata_index"
id: Mapped[int] = mapped_column(primary_key=True)
- extended_metadata_id: Mapped[Optional[int]] = mapped_column(
+ extended_metadata_id: Mapped[int | None] = mapped_column(
ForeignKey("extended_metadata.id", onupdate="CASCADE", ondelete="CASCADE"), index=True
)
- path: Mapped[Optional[str]] = mapped_column(String(255))
- value: Mapped[Optional[str]] = mapped_column(TEXT)
+ path: Mapped[str | None] = mapped_column(String(255))
+ value: Mapped[str | None] = mapped_column(TEXT)
extended_metadata: Mapped[Optional["ExtendedMetadata"]] = relationship(back_populates="children")
def __init__(self, extended_metadata, path, value):
@@ -7110,11 +7115,11 @@ class LibraryInfoAssociation(Base, RepresentById):
__tablename__ = "library_info_association"
id: Mapped[int] = mapped_column(primary_key=True)
- library_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library.id"), index=True)
- form_definition_id: Mapped[Optional[int]] = mapped_column(ForeignKey("form_definition.id"), index=True)
- form_values_id: Mapped[Optional[int]] = mapped_column(ForeignKey("form_values.id"), index=True)
- inheritable: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ library_id: Mapped[int | None] = mapped_column(ForeignKey("library.id"), index=True)
+ form_definition_id: Mapped[int | None] = mapped_column(ForeignKey("form_definition.id"), index=True)
+ form_values_id: Mapped[int | None] = mapped_column(ForeignKey("form_values.id"), index=True)
+ inheritable: Mapped[bool | None] = mapped_column(index=True, default=False)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
library: Mapped[Optional["Library"]] = relationship(
primaryjoin=(
@@ -7142,16 +7147,18 @@ class LibraryFolderInfoAssociation(Base, RepresentById):
__tablename__ = "library_folder_info_association"
id: Mapped[int] = mapped_column(primary_key=True)
- library_folder_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_folder.id"), index=True)
- form_definition_id: Mapped[Optional[int]] = mapped_column(ForeignKey("form_definition.id"), index=True)
- form_values_id: Mapped[Optional[int]] = mapped_column(ForeignKey("form_values.id"), index=True)
- inheritable: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ library_folder_id: Mapped[int | None] = mapped_column(ForeignKey("library_folder.id"), index=True)
+ form_definition_id: Mapped[int | None] = mapped_column(ForeignKey("form_definition.id"), index=True)
+ form_values_id: Mapped[int | None] = mapped_column(ForeignKey("form_values.id"), index=True)
+ inheritable: Mapped[bool | None] = mapped_column(index=True, default=False)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
folder: Mapped[Optional["LibraryFolder"]] = relationship(
primaryjoin=(
- lambda: (LibraryFolderInfoAssociation.library_folder_id == LibraryFolder.id)
- & (not_(LibraryFolderInfoAssociation.deleted))
+ lambda: (
+ (LibraryFolderInfoAssociation.library_folder_id == LibraryFolder.id)
+ & (not_(LibraryFolderInfoAssociation.deleted))
+ )
),
)
template: Mapped[Optional["FormDefinition"]] = relationship(
@@ -7172,20 +7179,22 @@ class LibraryDatasetDatasetInfoAssociation(Base, RepresentById):
__tablename__ = "library_dataset_dataset_info_association"
id: Mapped[int] = mapped_column(primary_key=True)
- library_dataset_dataset_association_id: Mapped[Optional[int]] = mapped_column(
+ library_dataset_dataset_association_id: Mapped[int | None] = mapped_column(
ForeignKey("library_dataset_dataset_association.id"), index=True
)
- form_definition_id: Mapped[Optional[int]] = mapped_column(ForeignKey("form_definition.id"), index=True)
- form_values_id: Mapped[Optional[int]] = mapped_column(ForeignKey("form_values.id"), index=True)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ form_definition_id: Mapped[int | None] = mapped_column(ForeignKey("form_definition.id"), index=True)
+ form_values_id: Mapped[int | None] = mapped_column(ForeignKey("form_values.id"), index=True)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
library_dataset_dataset_association: Mapped[Optional["LibraryDatasetDatasetAssociation"]] = relationship(
primaryjoin=(
lambda: (
- LibraryDatasetDatasetInfoAssociation.library_dataset_dataset_association_id
- == LibraryDatasetDatasetAssociation.id
+ (
+ LibraryDatasetDatasetInfoAssociation.library_dataset_dataset_association_id
+ == LibraryDatasetDatasetAssociation.id
+ )
+ & (not_(LibraryDatasetDatasetInfoAssociation.deleted))
)
- & (not_(LibraryDatasetDatasetInfoAssociation.deleted))
),
)
template: Mapped[Optional["FormDefinition"]] = relationship(
@@ -7212,15 +7221,13 @@ class ImplicitlyConvertedDatasetAssociation(Base, Serializable):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- hda_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
- ldda_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_dataset_dataset_association.id"), index=True)
- hda_parent_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
- ldda_parent_id: Mapped[Optional[int]] = mapped_column(
- ForeignKey("library_dataset_dataset_association.id"), index=True
- )
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- metadata_safe: Mapped[Optional[bool]] = mapped_column(index=True, default=True)
- type: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
+ hda_id: Mapped[int | None] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
+ ldda_id: Mapped[int | None] = mapped_column(ForeignKey("library_dataset_dataset_association.id"), index=True)
+ hda_parent_id: Mapped[int | None] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
+ ldda_parent_id: Mapped[int | None] = mapped_column(ForeignKey("library_dataset_dataset_association.id"), index=True)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ metadata_safe: Mapped[bool | None] = mapped_column(index=True, default=True)
+ type: Mapped[str | None] = mapped_column(TrimmedString(255))
parent_hda: Mapped[Optional["HistoryDatasetAssociation"]] = relationship(
primaryjoin=(lambda: ImplicitlyConvertedDatasetAssociation.hda_parent_id == HistoryDatasetAssociation.id),
@@ -7306,7 +7313,7 @@ DEFAULT_COLLECTION_NAME = "Unnamed Collection"
class CollectionStateSummary(NamedTuple):
- dbkeys: list[Union[str, None]]
+ dbkeys: list[str | None]
extensions: list[str]
states: dict[str, int]
deleted: int
@@ -7318,14 +7325,14 @@ class DatasetCollection(Base, Dictifiable, UsesAnnotations, Serializable):
id: Mapped[int] = mapped_column(primary_key=True)
collection_type: Mapped[str] = mapped_column(Unicode(255))
populated_state: Mapped[str] = mapped_column(TrimmedString(64), default="ok")
- populated_state_message: Mapped[Optional[str]] = mapped_column(TEXT)
- element_count: Mapped[Optional[int]]
+ populated_state_message: Mapped[str | None] = mapped_column(TEXT)
+ element_count: Mapped[int | None]
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
# if collection_type is 'record' (heterogenous collection)
- fields: Mapped[Optional[DATA_COLLECTION_FIELDS]] = mapped_column(JSONType)
+ fields: Mapped[DATA_COLLECTION_FIELDS | None] = mapped_column(JSONType)
# if collection_type is 'sample_sheet' (collection of rows that datasets with extra column metadata)
- column_definitions: Mapped[Optional[SampleSheetColumnDefinitions]] = mapped_column(JSONType)
+ column_definitions: Mapped[SampleSheetColumnDefinitions | None] = mapped_column(JSONType)
elements: Mapped[list["DatasetCollectionElement"]] = relationship(
primaryjoin=(lambda: DatasetCollection.id == DatasetCollectionElement.dataset_collection_id),
@@ -7363,22 +7370,21 @@ class DatasetCollection(Base, Dictifiable, UsesAnnotations, Serializable):
def _build_nested_collection_attributes_stmt(
self,
- collection_attributes: Optional[Iterable[str]] = None,
- element_attributes: Optional[Iterable[str]] = None,
- hda_attributes: Optional[Iterable[str]] = None,
- dataset_attributes: Optional[Iterable[str]] = None,
- dataset_permission_attributes: Optional[Iterable[str]] = None,
- return_entities: Optional[
+ collection_attributes: Iterable[str] | None = None,
+ element_attributes: Iterable[str] | None = None,
+ hda_attributes: Iterable[str] | None = None,
+ dataset_attributes: Iterable[str] | None = None,
+ dataset_permission_attributes: Iterable[str] | None = None,
+ return_entities: (
Iterable[
- Union[
- type[HistoryDatasetAssociation],
- type[Dataset],
- type[DatasetPermissions],
- type["DatasetCollection"],
- type["DatasetCollectionElement"],
- ]
+ type[HistoryDatasetAssociation]
+ | type[Dataset]
+ | type[DatasetPermissions]
+ | type["DatasetCollection"]
+ | type["DatasetCollectionElement"]
]
- ] = None,
+ | None
+ ) = None,
):
collection_attributes = collection_attributes or ()
element_attributes = element_attributes or ()
@@ -7610,7 +7616,6 @@ class DatasetCollection(Base, Dictifiable, UsesAnnotations, Serializable):
Returns (dbkeys, extensions, states, deleted) similar to HDCA method.
"""
if not hasattr(self, "_dataset_states_and_extensions_summary"):
-
stmt = self._build_nested_collection_attributes_stmt(
hda_attributes=("_metadata", "extension", "deleted"), dataset_attributes=("state",)
)
@@ -7894,7 +7899,7 @@ class DatasetCollection(Base, Dictifiable, UsesAnnotations, Serializable):
self,
destination: Optional["HistoryDatasetCollectionAssociation"] = None,
element_destination: Optional["History"] = None,
- dataset_instance_attributes: Optional[dict[str, Any]] = None,
+ dataset_instance_attributes: dict[str, Any] | None = None,
flush=True,
minimize_copies=False,
copy_hid=True,
@@ -8057,18 +8062,18 @@ class HistoryDatasetCollectionAssociation(
__tablename__ = "history_dataset_collection_association"
id: Mapped[int] = mapped_column(primary_key=True)
- collection_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dataset_collection.id"), index=True)
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)
- name: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- hid: Mapped[Optional[int]]
- visible: Mapped[Optional[bool]]
+ collection_id: Mapped[int | None] = mapped_column(ForeignKey("dataset_collection.id"), index=True)
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True)
+ name: Mapped[str | None] = mapped_column(TrimmedString(255))
+ hid: Mapped[int | None]
+ visible: Mapped[bool | None]
deleted: Mapped[bool] = mapped_column(default=False, nullable=True)
- copied_from_history_dataset_collection_association_id: Mapped[Optional[int]] = mapped_column(
+ copied_from_history_dataset_collection_association_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_collection_association.id")
)
- implicit_output_name: Mapped[Optional[str]] = mapped_column(Unicode(255))
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- implicit_collection_jobs_id: Mapped[Optional[int]] = mapped_column(
+ implicit_output_name: Mapped[str | None] = mapped_column(Unicode(255))
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ implicit_collection_jobs_id: Mapped[int | None] = mapped_column(
ForeignKey("implicit_collection_jobs.id"), index=True
)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
@@ -8085,8 +8090,9 @@ class HistoryDatasetCollectionAssociation(
)
implicit_input_collections: Mapped[list["ImplicitlyCreatedDatasetCollectionInput"]] = relationship(
primaryjoin=(
- lambda: HistoryDatasetCollectionAssociation.id
- == ImplicitlyCreatedDatasetCollectionInput.dataset_collection_id
+ lambda: (
+ HistoryDatasetCollectionAssociation.id == ImplicitlyCreatedDatasetCollectionInput.dataset_collection_id
+ )
),
)
implicit_collection_jobs = relationship("ImplicitCollectionJobs", uselist=False)
@@ -8269,14 +8275,14 @@ class HistoryDatasetCollectionAssociation(
flag_modified(self.collection, "collection_type")
@overload
- def to_hda_representative(self, multiple: Literal[False] = False) -> Optional[HistoryDatasetAssociation]: ...
+ def to_hda_representative(self, multiple: Literal[False] = False) -> HistoryDatasetAssociation | None: ...
@overload
def to_hda_representative(self, multiple: Literal[True]) -> list[HistoryDatasetAssociation]: ...
def to_hda_representative(
self, multiple: bool = False
- ) -> Union[list[HistoryDatasetAssociation], Optional[HistoryDatasetAssociation]]:
+ ) -> list[HistoryDatasetAssociation] | HistoryDatasetAssociation | None:
rval = []
for dataset in self.collection.dataset_elements:
rval.append(dataset.dataset_instance)
@@ -8366,12 +8372,12 @@ class HistoryDatasetCollectionAssociation(
def copy(
self,
- element_destination: Optional[History] = None,
- dataset_instance_attributes: Optional[dict[str, Any]] = None,
+ element_destination: History | None = None,
+ dataset_instance_attributes: dict[str, Any] | None = None,
flush: bool = True,
set_hid: bool = True,
minimize_copies: bool = False,
- target_user: Optional[User] = None,
+ target_user: User | None = None,
):
"""
Create a copy of this history dataset collection association. Copy
@@ -8454,7 +8460,7 @@ class HistoryDatasetCollectionAssociation(
return len(results) > 0
-HistoryItem: TypeAlias = Union[HistoryDatasetAssociation, HistoryDatasetCollectionAssociation]
+HistoryItem: TypeAlias = HistoryDatasetAssociation | HistoryDatasetCollectionAssociation
class LibraryDatasetCollectionAssociation(Base, DatasetCollectionInstance, RepresentById):
@@ -8463,10 +8469,10 @@ class LibraryDatasetCollectionAssociation(Base, DatasetCollectionInstance, Repre
__tablename__ = "library_dataset_collection_association"
id: Mapped[int] = mapped_column(primary_key=True)
- collection_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dataset_collection.id"), index=True)
- folder_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_folder.id"), index=True)
- name: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- deleted: Mapped[Optional[bool]] = mapped_column(default=False)
+ collection_id: Mapped[int | None] = mapped_column(ForeignKey("dataset_collection.id"), index=True)
+ folder_id: Mapped[int | None] = mapped_column(ForeignKey("library_folder.id"), index=True)
+ name: Mapped[str | None] = mapped_column(TrimmedString(255))
+ deleted: Mapped[bool | None] = mapped_column(default=False)
collection = relationship("DatasetCollection")
folder = relationship("LibraryFolder")
@@ -8507,13 +8513,13 @@ class DatasetCollectionElement(Base, Dictifiable, Serializable):
# Parent collection id describing what collection this element belongs to.
dataset_collection_id: Mapped[int] = mapped_column(ForeignKey("dataset_collection.id"), index=True)
# Child defined by this association - HDA, LDDA, or another dataset association...
- hda_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
- ldda_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_dataset_dataset_association.id"), index=True)
- child_collection_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dataset_collection.id"), index=True)
+ hda_id: Mapped[int | None] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
+ ldda_id: Mapped[int | None] = mapped_column(ForeignKey("library_dataset_dataset_association.id"), index=True)
+ child_collection_id: Mapped[int | None] = mapped_column(ForeignKey("dataset_collection.id"), index=True)
# Element index and identifier to define this parent-child relationship.
- element_index: Mapped[Optional[int]]
- element_identifier: Mapped[Optional[str]] = mapped_column(Unicode(255))
- columns: Mapped[Optional[SampleSheetRow]] = mapped_column(JSONType)
+ element_index: Mapped[int | None]
+ element_identifier: Mapped[str | None] = mapped_column(Unicode(255))
+ columns: Mapped[SampleSheetRow | None] = mapped_column(JSONType)
hda: Mapped[Optional["HistoryDatasetAssociation"]] = relationship(
"HistoryDatasetAssociation",
@@ -8545,7 +8551,7 @@ class DatasetCollectionElement(Base, Dictifiable, Serializable):
element=None,
element_index=None,
element_identifier=None,
- columns: Optional[SampleSheetRow] = None,
+ columns: SampleSheetRow | None = None,
):
if isinstance(element, HistoryDatasetAssociation):
self.hda = element
@@ -8589,7 +8595,7 @@ class DatasetCollectionElement(Base, Dictifiable, Serializable):
@property
def element_object(
self,
- ) -> Optional[Union[HistoryDatasetAssociation, LibraryDatasetDatasetAssociation, DatasetCollection]]:
+ ) -> HistoryDatasetAssociation | LibraryDatasetDatasetAssociation | DatasetCollection | None:
if self.hda:
return self.hda
elif self.ldda:
@@ -8600,9 +8606,7 @@ class DatasetCollectionElement(Base, Dictifiable, Serializable):
return None
@element_object.setter
- def element_object(
- self, value: Union[HistoryDatasetAssociation, LibraryDatasetDatasetAssociation, DatasetCollection]
- ):
+ def element_object(self, value: HistoryDatasetAssociation | LibraryDatasetDatasetAssociation | DatasetCollection):
if isinstance(value, HistoryDatasetAssociation):
self.hda = value
elif isinstance(value, LibraryDatasetDatasetAssociation):
@@ -8651,9 +8655,9 @@ class DatasetCollectionElement(Base, Dictifiable, Serializable):
def copy_to_collection(
self,
collection: DatasetCollection,
- destination: Optional[HistoryDatasetCollectionAssociation] = None,
- element_destination: Optional[History] = None,
- dataset_instance_attributes: Optional[dict[str, Any]] = None,
+ destination: HistoryDatasetCollectionAssociation | None = None,
+ element_destination: History | None = None,
+ dataset_instance_attributes: dict[str, Any] | None = None,
flush=True,
minimize_copies=False,
copy_hid=True,
@@ -8726,11 +8730,11 @@ class Event(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- message: Mapped[Optional[str]] = mapped_column(TrimmedString(1024))
- session_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_session.id", ondelete="SET NULL"), index=True)
- tool_id: Mapped[Optional[str]] = mapped_column(String(255))
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ message: Mapped[str | None] = mapped_column(TrimmedString(1024))
+ session_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_session.id", ondelete="SET NULL"), index=True)
+ tool_id: Mapped[str | None] = mapped_column(String(255))
history: Mapped[Optional["History"]] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -8743,18 +8747,18 @@ class GalaxySession(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- remote_host: Mapped[Optional[str]] = mapped_column(String(255))
- remote_addr: Mapped[Optional[str]] = mapped_column(String(255))
- referer: Mapped[Optional[str]] = mapped_column(TEXT)
- current_history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"))
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ remote_host: Mapped[str | None] = mapped_column(String(255))
+ remote_addr: Mapped[str | None] = mapped_column(String(255))
+ referer: Mapped[str | None] = mapped_column(TEXT)
+ current_history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"))
# unique 128 bit random number coerced to a string
- session_key: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True, unique=True)
- is_valid: Mapped[Optional[bool]] = mapped_column(default=False)
+ session_key: Mapped[str | None] = mapped_column(TrimmedString(255), index=True, unique=True)
+ is_valid: Mapped[bool | None] = mapped_column(default=False)
# saves a reference to the previous session so we have a way to chain them together
- prev_session_id: Mapped[Optional[int]]
- disk_usage: Mapped[Optional[Decimal]] = mapped_column(Numeric(15, 0), index=True)
- last_action: Mapped[Optional[datetime]]
+ prev_session_id: Mapped[int | None]
+ disk_usage: Mapped[Decimal | None] = mapped_column(Numeric(15, 0), index=True)
+ last_action: Mapped[datetime | None]
current_history: Mapped[Optional["History"]] = relationship()
histories: Mapped[list["GalaxySessionToHistoryAssociation"]] = relationship(
back_populates="galaxy_session",
@@ -8788,8 +8792,8 @@ class GalaxySessionToHistoryAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- session_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_session.id", ondelete="CASCADE"), index=True)
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)
+ session_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_session.id", ondelete="CASCADE"), index=True)
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True)
galaxy_session: Mapped[Optional["GalaxySession"]] = relationship(back_populates="histories")
history: Mapped[Optional["History"]] = relationship(back_populates="galaxy_sessions")
@@ -8816,16 +8820,16 @@ class StoredWorkflow(Base, HasTags, RepresentById, UsesCreateAndUpdateTime):
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, index=True, nullable=True)
user_id: Mapped[int] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- latest_workflow_id: Mapped[Optional[int]] = mapped_column(
+ latest_workflow_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow.id", use_alter=True, name="stored_workflow_latest_workflow_id_fk"), index=True
)
- name: Mapped[Optional[str]] = mapped_column(TEXT)
- deleted: Mapped[Optional[bool]] = mapped_column(default=False)
- hidden: Mapped[Optional[bool]] = mapped_column(default=False)
- importable: Mapped[Optional[bool]] = mapped_column(default=False)
- slug: Mapped[Optional[str]] = mapped_column(TEXT)
- from_path: Mapped[Optional[str]] = mapped_column(TEXT)
- published: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ name: Mapped[str | None] = mapped_column(TEXT)
+ deleted: Mapped[bool | None] = mapped_column(default=False)
+ hidden: Mapped[bool | None] = mapped_column(default=False)
+ importable: Mapped[bool | None] = mapped_column(default=False)
+ slug: Mapped[str | None] = mapped_column(TEXT)
+ from_path: Mapped[str | None] = mapped_column(TEXT)
+ published: Mapped[bool | None] = mapped_column(index=True, default=False)
user: Mapped["User"] = relationship(
primaryjoin=(lambda: User.id == StoredWorkflow.user_id),
@@ -8921,7 +8925,7 @@ class StoredWorkflow(Base, HasTags, RepresentById, UsesCreateAndUpdateTime):
self.workflows = listify(workflow)
self.hidden = hidden
- def get_internal_version(self, version: Optional[int] = None) -> "Workflow":
+ def get_internal_version(self, version: int | None = None) -> "Workflow":
if version is None:
return self.latest_workflow
if len(self.workflows) <= version:
@@ -8997,20 +9001,20 @@ class Workflow(Base, Dictifiable, RepresentById):
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
# workflows will belong to either a stored workflow or a parent/nesting workflow.
- stored_workflow_id: Mapped[Optional[int]] = mapped_column(ForeignKey("stored_workflow.id"), index=True)
- parent_workflow_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow.id"), index=True)
- name: Mapped[Optional[str]] = mapped_column(TEXT)
- has_cycles: Mapped[Optional[bool]]
- has_errors: Mapped[Optional[bool]]
- reports_config: Mapped[Optional[bytes]] = mapped_column(JSONType)
- creator_metadata: Mapped[Optional[list[dict[str, Any]]]] = mapped_column(JSONType)
- license: Mapped[Optional[str]] = mapped_column(TEXT)
- source_metadata: Mapped[Optional[dict[str, str]]] = mapped_column(JSONType)
- readme: Mapped[Optional[str]] = mapped_column(Text)
- logo_url: Mapped[Optional[str]] = mapped_column(Text)
- help: Mapped[Optional[str]] = mapped_column(Text)
- uuid: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType)
- doi: Mapped[Optional[list[str]]] = mapped_column(JSON)
+ stored_workflow_id: Mapped[int | None] = mapped_column(ForeignKey("stored_workflow.id"), index=True)
+ parent_workflow_id: Mapped[int | None] = mapped_column(ForeignKey("workflow.id"), index=True)
+ name: Mapped[str | None] = mapped_column(TEXT)
+ has_cycles: Mapped[bool | None]
+ has_errors: Mapped[bool | None]
+ reports_config: Mapped[bytes | None] = mapped_column(JSONType)
+ creator_metadata: Mapped[list[dict[str, Any]] | None] = mapped_column(JSONType)
+ license: Mapped[str | None] = mapped_column(TEXT)
+ source_metadata: Mapped[dict[str, str] | None] = mapped_column(JSONType)
+ readme: Mapped[str | None] = mapped_column(Text)
+ logo_url: Mapped[str | None] = mapped_column(Text)
+ help: Mapped[str | None] = mapped_column(Text)
+ uuid: Mapped[UUID | str | None] = mapped_column(UUIDType)
+ doi: Mapped[list[str] | None] = mapped_column(JSON)
steps: Mapped[list["WorkflowStep"]] = relationship(
"WorkflowStep",
@@ -9203,7 +9207,7 @@ class Workflow(Base, Dictifiable, RepresentById):
return f"Workflow[id={self.id}{extra}]"
-InputConnDictType = dict[str, Union[dict[str, Any], list[dict[str, Any]]]]
+InputConnDictType = dict[str, dict[str, Any] | list[dict[str, Any]]]
class WorkflowStep(Base, RepresentById, UsesCreateAndUpdateTime):
@@ -9219,21 +9223,21 @@ class WorkflowStep(Base, RepresentById, UsesCreateAndUpdateTime):
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
workflow_id: Mapped[int] = mapped_column(ForeignKey("workflow.id"), index=True)
- subworkflow_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow.id"), index=True)
- dynamic_tool_id: Mapped[Optional[int]] = mapped_column(ForeignKey("dynamic_tool.id"), index=True)
- type: Mapped[Optional[str]] = mapped_column(String(64))
- tool_id: Mapped[Optional[str]] = mapped_column(TEXT)
- tool_version: Mapped[Optional[str]] = mapped_column(TEXT)
- tool_inputs: Mapped[Optional[dict[str, Any]]] = mapped_column(JSONType)
- tool_errors: Mapped[Optional[bytes]] = mapped_column(JSONType)
- position: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
- config: Mapped[Optional[bytes]] = mapped_column(JSONType)
+ subworkflow_id: Mapped[int | None] = mapped_column(ForeignKey("workflow.id"), index=True)
+ dynamic_tool_id: Mapped[int | None] = mapped_column(ForeignKey("dynamic_tool.id"), index=True)
+ type: Mapped[str | None] = mapped_column(String(64))
+ tool_id: Mapped[str | None] = mapped_column(TEXT)
+ tool_version: Mapped[str | None] = mapped_column(TEXT)
+ tool_inputs: Mapped[dict[str, Any] | None] = mapped_column(JSONType)
+ tool_errors: Mapped[bytes | None] = mapped_column(JSONType)
+ position: Mapped[bytes | None] = mapped_column(MutableJSONType)
+ config: Mapped[bytes | None] = mapped_column(JSONType)
order_index: Mapped[int]
- when_expression: Mapped[Optional[bytes]] = mapped_column(JSONType)
- uuid: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType)
- label: Mapped[Optional[str]] = mapped_column(Unicode(255))
+ when_expression: Mapped[bytes | None] = mapped_column(JSONType)
+ uuid: Mapped[UUID | str | None] = mapped_column(UUIDType)
+ label: Mapped[str | None] = mapped_column(Unicode(255))
temp_input_connections = None
- parent_comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_comment.id"), index=True)
+ parent_comment_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_comment.id"), index=True)
parent_comment: Mapped[Optional["WorkflowComment"]] = relationship(
primaryjoin=(lambda: WorkflowComment.id == WorkflowStep.parent_comment_id),
@@ -9277,9 +9281,9 @@ class WorkflowStep(Base, RepresentById, UsesCreateAndUpdateTime):
self._inputs_by_name = None
# Injected attributes
# TODO: code using these should be refactored to not depend on these non-persistent fields
- self.module: Optional[WorkflowModule]
- self.state: Optional[DefaultToolState]
- self.upgrade_messages: Optional[dict]
+ self.module: WorkflowModule | None
+ self.state: DefaultToolState | None
+ self.upgrade_messages: dict | None
@reconstructor
def init_on_load(self):
@@ -9515,13 +9519,13 @@ class WorkflowStep(Base, RepresentById, UsesCreateAndUpdateTime):
)
@property
- def effective_label(self) -> Optional[str]:
+ def effective_label(self) -> str | None:
if (label := self.label) is not None:
return label
elif self.is_input_type:
tool_inputs = self.tool_inputs
if tool_inputs is not None:
- return cast(Optional[str], tool_inputs.get("name"))
+ return cast(str | None, tool_inputs.get("name"))
return None
def clear_module_extras(self):
@@ -9547,15 +9551,15 @@ class WorkflowStepInput(Base, RepresentById):
)
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"), index=True)
- name: Mapped[Optional[str]] = mapped_column(TEXT)
- merge_type: Mapped[Optional[str]] = mapped_column(TEXT)
- scatter_type: Mapped[Optional[str]] = mapped_column(TEXT)
- value_from: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
- value_from_type: Mapped[Optional[str]] = mapped_column(TEXT)
- default_value: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
- default_value_set: Mapped[Optional[bool]] = mapped_column(default=False)
- runtime_value: Mapped[Optional[bool]] = mapped_column(default=False)
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"), index=True)
+ name: Mapped[str | None] = mapped_column(TEXT)
+ merge_type: Mapped[str | None] = mapped_column(TEXT)
+ scatter_type: Mapped[str | None] = mapped_column(TEXT)
+ value_from: Mapped[bytes | None] = mapped_column(MutableJSONType)
+ value_from_type: Mapped[str | None] = mapped_column(TEXT)
+ default_value: Mapped[bytes | None] = mapped_column(MutableJSONType)
+ default_value_set: Mapped[bool | None] = mapped_column(default=False)
+ runtime_value: Mapped[bool | None] = mapped_column(default=False)
workflow_step: Mapped[Optional["WorkflowStep"]] = relationship(
back_populates="inputs",
@@ -9588,10 +9592,10 @@ class WorkflowStepConnection(Base, RepresentById):
__tablename__ = "workflow_step_connection"
id: Mapped[int] = mapped_column(primary_key=True)
- output_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"), index=True)
- input_step_input_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step_input.id"), index=True)
- output_name: Mapped[Optional[str]] = mapped_column(TEXT)
- input_subworkflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"), index=True)
+ output_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"), index=True)
+ input_step_input_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step_input.id"), index=True)
+ output_name: Mapped[str | None] = mapped_column(TEXT)
+ input_subworkflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"), index=True)
input_step_input: Mapped["WorkflowStepInput"] = relationship(
"WorkflowStepInput",
@@ -9625,7 +9629,7 @@ class WorkflowStepConnection(Base, RepresentById):
return self.input_step_input.name
@property
- def input_step(self) -> Optional[WorkflowStep]:
+ def input_step(self) -> WorkflowStep | None:
return self.input_step_input.workflow_step
@property
@@ -9645,9 +9649,9 @@ class WorkflowOutput(Base, Serializable):
id: Mapped[int] = mapped_column(primary_key=True)
workflow_step_id: Mapped[int] = mapped_column(ForeignKey("workflow_step.id"), index=True)
- output_name: Mapped[Optional[str]] = mapped_column(String(255))
- label: Mapped[Optional[str]] = mapped_column(Unicode(255))
- uuid: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType)
+ output_name: Mapped[str | None] = mapped_column(String(255))
+ label: Mapped[str | None] = mapped_column(Unicode(255))
+ uuid: Mapped[UUID | str | None] = mapped_column(UUIDType)
workflow_step: Mapped["WorkflowStep"] = relationship(
back_populates="workflow_outputs",
primaryjoin=(lambda: WorkflowStep.id == WorkflowOutput.workflow_step_id),
@@ -9684,14 +9688,14 @@ class WorkflowComment(Base, RepresentById):
__tablename__ = "workflow_comment"
id: Mapped[int] = mapped_column(primary_key=True)
- order_index: Mapped[Optional[int]]
+ order_index: Mapped[int | None]
workflow_id: Mapped[int] = mapped_column(ForeignKey("workflow.id"), index=True)
- position: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
- size: Mapped[Optional[bytes]] = mapped_column(JSONType)
- type: Mapped[Optional[str]] = mapped_column(String(16))
- color: Mapped[Optional[str]] = mapped_column(String(16))
- data: Mapped[Optional[bytes]] = mapped_column(JSONType)
- parent_comment_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_comment.id"), index=True)
+ position: Mapped[bytes | None] = mapped_column(MutableJSONType)
+ size: Mapped[bytes | None] = mapped_column(JSONType)
+ type: Mapped[str | None] = mapped_column(String(16))
+ color: Mapped[str | None] = mapped_column(String(16))
+ data: Mapped[bytes | None] = mapped_column(JSONType)
+ parent_comment_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_comment.id"), index=True)
workflow: Mapped["Workflow"] = relationship(
primaryjoin=(lambda: Workflow.id == WorkflowComment.workflow_id),
@@ -9773,17 +9777,19 @@ class StoredWorkflowMenuEntry(Base, RepresentById):
__tablename__ = "stored_workflow_menu_entry"
id: Mapped[int] = mapped_column(primary_key=True)
- stored_workflow_id: Mapped[Optional[int]] = mapped_column(ForeignKey("stored_workflow.id"), index=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- order_index: Mapped[Optional[int]]
+ stored_workflow_id: Mapped[int | None] = mapped_column(ForeignKey("stored_workflow.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ order_index: Mapped[int | None]
stored_workflow: Mapped[Optional["StoredWorkflow"]] = relationship()
user: Mapped[Optional["User"]] = relationship(
back_populates="stored_workflow_menu_entries",
primaryjoin=(
- lambda: (StoredWorkflowMenuEntry.user_id == User.id)
- & (StoredWorkflowMenuEntry.stored_workflow_id == StoredWorkflow.id)
- & not_(StoredWorkflow.deleted)
+ lambda: (
+ (StoredWorkflowMenuEntry.user_id == User.id)
+ & (StoredWorkflowMenuEntry.stored_workflow_id == StoredWorkflow.id)
+ & not_(StoredWorkflow.deleted)
+ )
),
)
@@ -9809,12 +9815,12 @@ class WorkflowInvocation(Base, UsesCreateAndUpdateTime, Dictifiable, Serializabl
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, index=True, nullable=True)
workflow_id: Mapped[int] = mapped_column(ForeignKey("workflow.id"), index=True)
- state: Mapped[Optional[str]] = mapped_column(TrimmedString(64), index=True)
- scheduler: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- handler: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- uuid: Mapped[Optional[Union[UUID]]] = mapped_column(UUIDType())
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)
- on_complete: Mapped[Optional[list]] = mapped_column(JSON)
+ state: Mapped[str | None] = mapped_column(TrimmedString(64), index=True)
+ scheduler: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ handler: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ uuid: Mapped[UUID | None] = mapped_column(UUIDType())
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True)
+ on_complete: Mapped[list | None] = mapped_column(JSON)
history = relationship("History", back_populates="workflow_invocations")
input_parameters = relationship("WorkflowRequestInputParameter", back_populates="workflow_invocation")
@@ -9885,7 +9891,7 @@ class WorkflowInvocation(Base, UsesCreateAndUpdateTime, Dictifiable, Serializabl
if self.state is None:
raise Exception("Workflow invocation without state, this should not happen")
- def get_last_workflow_invocation_step_update_time(self) -> Optional[datetime]:
+ def get_last_workflow_invocation_step_update_time(self) -> datetime | None:
session = required_object_session(self)
stmt = select(func.max(WorkflowInvocationStep.update_time)).where(
WorkflowInvocationStep.workflow_invocation_id == self.id
@@ -10388,7 +10394,7 @@ class WorkflowInvocation(Base, UsesCreateAndUpdateTime, Dictifiable, Serializabl
else:
request_to_content.workflow_step = step
- request: Optional[dict[str, Any]] = None
+ request: dict[str, Any] | None = None
if isinstance(content, InputWithRequest):
request = content.request
content = content.input
@@ -10510,19 +10516,20 @@ class WorkflowInvocationToSubworkflowInvocationAssociation(Base, Dictifiable, Re
__tablename__ = "workflow_invocation_to_subworkflow_invocation_association"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_invocation_id: Mapped[Optional[int]] = mapped_column(
+ workflow_invocation_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_invocation.id", name="fk_wfi_swi_wfi"), index=True
)
- subworkflow_invocation_id: Mapped[Optional[int]] = mapped_column(
+ subworkflow_invocation_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_invocation.id", name="fk_wfi_swi_swi"), index=True
)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id", name="fk_wfi_swi_ws"))
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id", name="fk_wfi_swi_ws"))
subworkflow_invocation = relationship(
"WorkflowInvocation",
primaryjoin=(
- lambda: WorkflowInvocationToSubworkflowInvocationAssociation.subworkflow_invocation_id
- == WorkflowInvocation.id
+ lambda: (
+ WorkflowInvocationToSubworkflowInvocationAssociation.subworkflow_invocation_id == WorkflowInvocation.id
+ )
),
uselist=False,
)
@@ -10543,15 +10550,15 @@ class WorkflowInvocationMessage(Base, Dictifiable, Serializable):
__tablename__ = "workflow_invocation_message"
id: Mapped[int] = mapped_column(primary_key=True)
workflow_invocation_id: Mapped[int] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
- reason: Mapped[Optional[str]] = mapped_column(String(32))
- details: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- output_name: Mapped[Optional[str]] = mapped_column(String(255))
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"))
- dependent_workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"))
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"))
- hda_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history_dataset_association.id"))
- hdca_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history_dataset_collection_association.id"))
- workflow_step_index_path: Mapped[Optional[list[int]]] = mapped_column(JSON)
+ reason: Mapped[str | None] = mapped_column(String(32))
+ details: Mapped[str | None] = mapped_column(TrimmedString(255))
+ output_name: Mapped[str | None] = mapped_column(String(255))
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"))
+ dependent_workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"))
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"))
+ hda_id: Mapped[int | None] = mapped_column(ForeignKey("history_dataset_association.id"))
+ hdca_id: Mapped[int | None] = mapped_column(ForeignKey("history_dataset_collection_association.id"))
+ workflow_step_index_path: Mapped[list[int] | None] = mapped_column(JSON)
workflow_invocation: Mapped["WorkflowInvocation"] = relationship(back_populates="messages", lazy=True)
workflow_step: Mapped[Optional["WorkflowStep"]] = relationship(foreign_keys=workflow_step_id, lazy=True)
@@ -10581,9 +10588,9 @@ class WorkflowInvocationCompletion(Base, RepresentById):
workflow_invocation_id: Mapped[int] = mapped_column(ForeignKey("workflow_invocation.id"), index=True, unique=True)
completion_time: Mapped[datetime] = mapped_column(default=now)
# Summary of final job states: {"ok": 5, "error": 1, "skipped": 2}
- job_state_summary: Mapped[Optional[dict[str, Any]]] = mapped_column(JSON)
+ job_state_summary: Mapped[dict[str, Any] | None] = mapped_column(JSON)
# Hooks that have been executed (for idempotency)
- hooks_executed: Mapped[Optional[list[str]]] = mapped_column(JSON)
+ hooks_executed: Mapped[list[str] | None] = mapped_column(JSON)
workflow_invocation: Mapped["WorkflowInvocation"] = relationship(back_populates="completion")
@@ -10605,10 +10612,10 @@ class EffectiveOutput(TypedDict):
class WorkflowInvocationStepObjectStores(NamedTuple):
- preferred_object_store_id: Optional[str]
- preferred_outputs_object_store_id: Optional[str]
- preferred_intermediate_object_store_id: Optional[str]
- step_effective_outputs: Optional[list["EffectiveOutput"]]
+ preferred_object_store_id: str | None
+ preferred_outputs_object_store_id: str | None
+ preferred_intermediate_object_store_id: str | None
+ step_effective_outputs: list["EffectiveOutput"] | None
def is_output_name_an_effective_output(self, output_name: str) -> bool:
if self.step_effective_outputs is None:
@@ -10638,12 +10645,12 @@ class WorkflowInvocationStep(Base, Dictifiable, Serializable):
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
workflow_invocation_id: Mapped[int] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
workflow_step_id: Mapped[int] = mapped_column(ForeignKey("workflow_step.id"), index=True)
- state: Mapped[Optional[str]] = mapped_column(TrimmedString(64), index=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- implicit_collection_jobs_id: Mapped[Optional[int]] = mapped_column(
+ state: Mapped[str | None] = mapped_column(TrimmedString(64), index=True)
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ implicit_collection_jobs_id: Mapped[int | None] = mapped_column(
ForeignKey("implicit_collection_jobs.id"), index=True
)
- action: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
+ action: Mapped[bytes | None] = mapped_column(MutableJSONType)
workflow_step: Mapped[WorkflowStep] = relationship("WorkflowStep")
job: Mapped[Optional["Job"]] = relationship(back_populates="workflow_invocation_step", uselist=False)
@@ -10672,7 +10679,7 @@ class WorkflowInvocationStep(Base, Dictifiable, Serializable):
order_index: Mapped[int] = column_property(
select(WorkflowStep.order_index).where(WorkflowStep.id == workflow_step_id).scalar_subquery()
)
- subworkflow_invocation_id: Mapped[Optional[int]] = column_property(
+ subworkflow_invocation_id: Mapped[int | None] = column_property(
select(WorkflowInvocationToSubworkflowInvocationAssociation.subworkflow_invocation_id)
.where(
and_(
@@ -10786,7 +10793,7 @@ class WorkflowInvocationStep(Base, Dictifiable, Serializable):
preferred_object_store_id = None
preferred_outputs_object_store_id = None
preferred_intermediate_object_store_id = None
- step_effective_outputs: Optional[list[EffectiveOutput]] = None
+ step_effective_outputs: list[EffectiveOutput] | None = None
workflow_invocation = self.workflow_invocation
for input_parameter in workflow_invocation.input_parameters:
@@ -10902,12 +10909,12 @@ class WorkflowRequestInputParameter(Base, Dictifiable, Serializable):
__tablename__ = "workflow_request_input_parameters"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_invocation_id: Mapped[Optional[int]] = mapped_column(
+ workflow_invocation_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_invocation.id", onupdate="CASCADE", ondelete="CASCADE"), index=True
)
- name: Mapped[Optional[str]] = mapped_column(Unicode(255))
- value: Mapped[Optional[str]] = mapped_column(TEXT)
- type: Mapped[Optional[str]] = mapped_column(Unicode(255))
+ name: Mapped[str | None] = mapped_column(Unicode(255))
+ value: Mapped[str | None] = mapped_column(TEXT)
+ type: Mapped[str | None] = mapped_column(Unicode(255))
workflow_invocation: Mapped[Optional["WorkflowInvocation"]] = relationship(back_populates="input_parameters")
dict_collection_visible_keys = ["id", "name", "value", "type"]
@@ -10932,11 +10939,11 @@ class WorkflowRequestStepState(Base, Dictifiable, Serializable):
__tablename__ = "workflow_request_step_states"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_invocation_id: Mapped[Optional[int]] = mapped_column(
+ workflow_invocation_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_invocation.id", onupdate="CASCADE", ondelete="CASCADE"), index=True
)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"))
- value: Mapped[Optional[dict[str, Any]]] = mapped_column(MutableJSONType)
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"))
+ value: Mapped[dict[str, Any] | None] = mapped_column(MutableJSONType)
workflow_step: Mapped[Optional["WorkflowStep"]] = relationship()
workflow_invocation: Mapped[Optional["WorkflowInvocation"]] = relationship(back_populates="step_states")
@@ -10955,11 +10962,11 @@ class WorkflowRequestToInputDatasetAssociation(Base, Dictifiable, Serializable):
__tablename__ = "workflow_request_to_input_dataset"
id: Mapped[int] = mapped_column(primary_key=True)
- name: Mapped[Optional[str]] = mapped_column(String(255))
- workflow_invocation_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"))
- dataset_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
- request: Mapped[Optional[dict]] = mapped_column(JSONType)
+ name: Mapped[str | None] = mapped_column(String(255))
+ workflow_invocation_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"))
+ dataset_id: Mapped[int | None] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
+ request: Mapped[dict | None] = mapped_column(JSONType)
workflow_step: Mapped[Optional["WorkflowStep"]] = relationship()
dataset: Mapped[Optional["HistoryDatasetAssociation"]] = relationship()
@@ -10984,10 +10991,10 @@ class WorkflowRequestToInputDatasetCollectionAssociation(Base, Dictifiable, Seri
__tablename__ = "workflow_request_to_input_collection_dataset"
id: Mapped[int] = mapped_column(primary_key=True)
- name: Mapped[Optional[str]] = mapped_column(String(255))
- workflow_invocation_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"))
- dataset_collection_id: Mapped[Optional[int]] = mapped_column(
+ name: Mapped[str | None] = mapped_column(String(255))
+ workflow_invocation_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"))
+ dataset_collection_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_collection_association.id"), index=True
)
workflow_step: Mapped[Optional["WorkflowStep"]] = relationship()
@@ -10995,7 +11002,7 @@ class WorkflowRequestToInputDatasetCollectionAssociation(Base, Dictifiable, Seri
workflow_invocation: Mapped[Optional["WorkflowInvocation"]] = relationship(
back_populates="input_dataset_collections"
)
- request: Mapped[Optional[dict]] = mapped_column(JSONType)
+ request: Mapped[dict | None] = mapped_column(JSONType)
history_content_type = "dataset_collection"
dict_collection_visible_keys = ["id", "workflow_invocation_id", "workflow_step_id", "dataset_collection_id", "name"]
@@ -11016,10 +11023,10 @@ class WorkflowRequestInputStepParameter(Base, Dictifiable, Serializable):
__tablename__ = "workflow_request_input_step_parameter"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_invocation_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"))
- parameter_value: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
- request: Mapped[Optional[dict]] = mapped_column(JSONType)
+ workflow_invocation_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"))
+ parameter_value: Mapped[bytes | None] = mapped_column(MutableJSONType)
+ request: Mapped[dict | None] = mapped_column(JSONType)
workflow_step: Mapped[Optional["WorkflowStep"]] = relationship()
workflow_invocation: Mapped[Optional["WorkflowInvocation"]] = relationship(back_populates="input_step_parameters")
@@ -11039,10 +11046,10 @@ class WorkflowInvocationOutputDatasetAssociation(Base, Dictifiable, Serializable
__tablename__ = "workflow_invocation_output_dataset_association"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_invocation_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"), index=True)
- dataset_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
- workflow_output_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_output.id"), index=True)
+ workflow_invocation_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"), index=True)
+ dataset_id: Mapped[int | None] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
+ workflow_output_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_output.id"), index=True)
workflow_invocation: Mapped[Optional["WorkflowInvocation"]] = relationship(back_populates="output_datasets")
workflow_step: Mapped[Optional["WorkflowStep"]] = relationship()
dataset: Mapped[Optional["HistoryDatasetAssociation"]] = relationship()
@@ -11065,16 +11072,16 @@ class WorkflowInvocationOutputDatasetCollectionAssociation(Base, Dictifiable, Se
__tablename__ = "workflow_invocation_output_dataset_collection_association"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_invocation_id: Mapped[Optional[int]] = mapped_column(
+ workflow_invocation_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_invocation.id", name="fk_wiodca_wii"), index=True
)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(
+ workflow_step_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_step.id", name="fk_wiodca_wsi"), index=True
)
- dataset_collection_id: Mapped[Optional[int]] = mapped_column(
+ dataset_collection_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_collection_association.id", name="fk_wiodca_dci"), index=True
)
- workflow_output_id: Mapped[Optional[int]] = mapped_column(
+ workflow_output_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_output.id", name="fk_wiodca_woi"), index=True
)
@@ -11104,10 +11111,10 @@ class WorkflowInvocationOutputValue(Base, Dictifiable, Serializable):
__tablename__ = "workflow_invocation_output_value"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_invocation_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_step.id"))
- workflow_output_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow_output.id"), index=True)
- value: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
+ workflow_invocation_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_invocation.id"), index=True)
+ workflow_step_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_step.id"))
+ workflow_output_id: Mapped[int | None] = mapped_column(ForeignKey("workflow_output.id"), index=True)
+ value: Mapped[bytes | None] = mapped_column(MutableJSONType)
workflow_invocation: Mapped[Optional["WorkflowInvocation"]] = relationship(back_populates="output_values")
@@ -11142,11 +11149,11 @@ class WorkflowInvocationStepOutputDatasetAssociation(Base, Dictifiable, Represen
__tablename__ = "workflow_invocation_step_output_dataset_association"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_invocation_step_id: Mapped[Optional[int]] = mapped_column(
+ workflow_invocation_step_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_invocation_step.id"), index=True
)
- dataset_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
- output_name: Mapped[Optional[str]] = mapped_column(String(255))
+ dataset_id: Mapped[int | None] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
+ output_name: Mapped[str | None] = mapped_column(String(255))
workflow_invocation_step: Mapped[Optional["WorkflowInvocationStep"]] = relationship(
back_populates="output_datasets"
)
@@ -11161,16 +11168,16 @@ class WorkflowInvocationStepOutputDatasetCollectionAssociation(Base, Dictifiable
__tablename__ = "workflow_invocation_step_output_dataset_collection_association"
id: Mapped[int] = mapped_column(primary_key=True)
- workflow_invocation_step_id: Mapped[Optional[int]] = mapped_column(
+ workflow_invocation_step_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_invocation_step.id", name="fk_wisodca_wisi"), index=True
)
- workflow_step_id: Mapped[Optional[int]] = mapped_column(
+ workflow_step_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_step.id", name="fk_wisodca_wsi"), index=True
)
- dataset_collection_id: Mapped[Optional[int]] = mapped_column(
+ dataset_collection_id: Mapped[int | None] = mapped_column(
ForeignKey("history_dataset_collection_association.id", name="fk_wisodca_dci"), index=True
)
- output_name: Mapped[Optional[str]] = mapped_column(String(255))
+ output_name: Mapped[str | None] = mapped_column(String(255))
workflow_invocation_step: Mapped[Optional["WorkflowInvocationStep"]] = relationship(
back_populates="output_dataset_collections"
@@ -11184,15 +11191,15 @@ class MetadataFile(Base, StorableObject, Serializable):
__tablename__ = "metadata_file"
id: Mapped[int] = mapped_column(primary_key=True)
- name: Mapped[Optional[str]] = mapped_column(TEXT)
- hda_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
- lda_id: Mapped[Optional[int]] = mapped_column(ForeignKey("library_dataset_dataset_association.id"), index=True)
+ name: Mapped[str | None] = mapped_column(TEXT)
+ hda_id: Mapped[int | None] = mapped_column(ForeignKey("history_dataset_association.id"), index=True)
+ lda_id: Mapped[int | None] = mapped_column(ForeignKey("library_dataset_dataset_association.id"), index=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
- object_store_id: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- uuid: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType(), index=True)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- purged: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ object_store_id: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ uuid: Mapped[UUID | str | None] = mapped_column(UUIDType(), index=True)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ purged: Mapped[bool | None] = mapped_column(index=True, default=False)
history_dataset: Mapped[Optional["HistoryDatasetAssociation"]] = relationship()
library_dataset: Mapped[Optional["LibraryDatasetDatasetAssociation"]] = relationship()
@@ -11270,16 +11277,16 @@ class FormDefinition(Base, Dictifiable, RepresentById):
__tablename__ = "form_definition"
id: Mapped[int] = mapped_column(primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(default=now, onupdate=now)
+ create_time: Mapped[datetime | None] = mapped_column(default=now)
+ update_time: Mapped[datetime | None] = mapped_column(default=now, onupdate=now)
name: Mapped[str] = mapped_column(TrimmedString(255))
- desc: Mapped[Optional[str]] = mapped_column(TEXT)
+ desc: Mapped[str | None] = mapped_column(TEXT)
form_definition_current_id: Mapped[int] = mapped_column(
ForeignKey("form_definition_current.id", use_alter=True), index=True
)
- fields: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
- type: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- layout: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
+ fields: Mapped[bytes | None] = mapped_column(MutableJSONType)
+ type: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ layout: Mapped[bytes | None] = mapped_column(MutableJSONType)
form_definition_current: Mapped["FormDefinitionCurrent"] = relationship(
back_populates="forms",
primaryjoin=(lambda: FormDefinitionCurrent.id == FormDefinition.form_definition_current_id),
@@ -11343,8 +11350,8 @@ class FormDefinitionCurrent(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- latest_form_id: Mapped[Optional[int]] = mapped_column(ForeignKey("form_definition.id"), index=True)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ latest_form_id: Mapped[int | None] = mapped_column(ForeignKey("form_definition.id"), index=True)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
forms: Mapped[list["FormDefinition"]] = relationship(
back_populates="form_definition_current",
cascade="all, delete-orphan",
@@ -11365,8 +11372,8 @@ class FormValues(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- form_definition_id: Mapped[Optional[int]] = mapped_column(ForeignKey("form_definition.id"), index=True)
- content: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
+ form_definition_id: Mapped[int | None] = mapped_column(ForeignKey("form_definition.id"), index=True)
+ content: Mapped[bytes | None] = mapped_column(MutableJSONType)
form_definition: Mapped[Optional["FormDefinition"]] = relationship(
primaryjoin=(lambda: FormValues.form_definition_id == FormDefinition.id)
)
@@ -11382,18 +11389,18 @@ class UserAddress(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- desc: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ desc: Mapped[str | None] = mapped_column(TrimmedString(255))
name: Mapped[str] = mapped_column(TrimmedString(255))
- institution: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
+ institution: Mapped[str | None] = mapped_column(TrimmedString(255))
address: Mapped[str] = mapped_column(TrimmedString(255))
city: Mapped[str] = mapped_column(TrimmedString(255))
state: Mapped[str] = mapped_column(TrimmedString(255))
postal_code: Mapped[str] = mapped_column(TrimmedString(255))
country: Mapped[str] = mapped_column(TrimmedString(255))
- phone: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- purged: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
+ phone: Mapped[str | None] = mapped_column(TrimmedString(255))
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ purged: Mapped[bool | None] = mapped_column(index=True, default=False)
# `desc` needs to be fully qualified because it is shadowed by `desc` Column defined above
# TODO: db migration to rename column, then use `desc`
user: Mapped[Optional["User"]] = relationship(back_populates="addresses", order_by=sqlalchemy.desc("update_time"))
@@ -11417,12 +11424,12 @@ class PSAAssociation(Base, AssociationMixin, RepresentById):
__tablename__ = "psa_association"
id: Mapped[int] = mapped_column(primary_key=True)
- server_url: Mapped[Optional[str]] = mapped_column(VARCHAR(255)) # type: ignore[assignment] # needed for social-auth-core Mixin class attributes
- handle: Mapped[Optional[str]] = mapped_column(VARCHAR(255)) # type: ignore[assignment]
- secret: Mapped[Optional[str]] = mapped_column(VARCHAR(255)) # type: ignore[assignment]
- issued: Mapped[Optional[int]] # type: ignore[assignment]
- lifetime: Mapped[Optional[int]] # type: ignore[assignment]
- assoc_type: Mapped[Optional[str]] = mapped_column(VARCHAR(64)) # type: ignore[assignment]
+ server_url: Mapped[str | None] = mapped_column(VARCHAR(255)) # type: ignore[assignment] # needed for social-auth-core Mixin class attributes
+ handle: Mapped[str | None] = mapped_column(VARCHAR(255)) # type: ignore[assignment]
+ secret: Mapped[str | None] = mapped_column(VARCHAR(255)) # type: ignore[assignment]
+ issued: Mapped[int | None] # type: ignore[assignment]
+ lifetime: Mapped[int | None] # type: ignore[assignment]
+ assoc_type: Mapped[str | None] = mapped_column(VARCHAR(64)) # type: ignore[assignment]
# This static property is set at: galaxy.authnz.psa_authnz.PSAAuthnz
sa_session = None
@@ -11479,8 +11486,8 @@ class PSACode(Base, CodeMixin, RepresentById):
__table_args__ = (UniqueConstraint("code", "email"),)
id: Mapped[int] = mapped_column(primary_key=True)
- email: Mapped[Optional[str]] = mapped_column(VARCHAR(200)) # type: ignore[assignment]
- code: Mapped[Optional[str]] = mapped_column(VARCHAR(32)) # type: ignore[assignment]
+ email: Mapped[str | None] = mapped_column(VARCHAR(200)) # type: ignore[assignment]
+ code: Mapped[str | None] = mapped_column(VARCHAR(32)) # type: ignore[assignment]
# This static property is set at: galaxy.authnz.psa_authnz.PSAAuthnz
sa_session = None
@@ -11506,9 +11513,9 @@ class PSANonce(Base, NonceMixin, RepresentById):
__tablename__ = "psa_nonce"
id: Mapped[int] = mapped_column(primary_key=True)
- server_url: Mapped[Optional[str]] = mapped_column(VARCHAR(255)) # type: ignore[assignment]
- timestamp: Mapped[Optional[int]] # type: ignore[assignment]
- salt: Mapped[Optional[str]] = mapped_column(VARCHAR(40)) # type: ignore[assignment]
+ server_url: Mapped[str | None] = mapped_column(VARCHAR(255)) # type: ignore[assignment]
+ timestamp: Mapped[int | None] # type: ignore[assignment]
+ salt: Mapped[str | None] = mapped_column(VARCHAR(40)) # type: ignore[assignment]
# This static property is set at: galaxy.authnz.psa_authnz.PSAAuthnz
sa_session = None
@@ -11542,10 +11549,10 @@ class PSAPartial(Base, PartialMixin, RepresentById):
__tablename__ = "psa_partial"
id: Mapped[int] = mapped_column(primary_key=True)
- token: Mapped[Optional[str]] = mapped_column(VARCHAR(32)) # type: ignore[assignment]
- data: Mapped[Optional[str]] = mapped_column(TEXT) # type: ignore[assignment]
- next_step: Mapped[Optional[int]] # type: ignore[assignment]
- backend: Mapped[Optional[str]] = mapped_column(VARCHAR(32)) # type: ignore[assignment]
+ token: Mapped[str | None] = mapped_column(VARCHAR(32)) # type: ignore[assignment]
+ data: Mapped[str | None] = mapped_column(TEXT) # type: ignore[assignment]
+ next_step: Mapped[int | None] # type: ignore[assignment]
+ backend: Mapped[str | None] = mapped_column(VARCHAR(32)) # type: ignore[assignment]
# This static property is set at: galaxy.authnz.psa_authnz.PSAAuthnz
sa_session = None
@@ -11584,20 +11591,20 @@ class UserAuthnzToken(Base, UserMixin, RepresentById):
__table_args__ = (UniqueConstraint("provider", "uid"),)
id: Mapped[int] = mapped_column(primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- uid: Mapped[Optional[str]] = mapped_column(VARCHAR(255)) # type: ignore[assignment]
- provider: Mapped[Optional[str]] = mapped_column(VARCHAR(32)) # type: ignore[assignment]
- extra_data: Mapped[Optional[dict[str, Any]]] = mapped_column( # type: ignore[assignment, unused-ignore]
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ uid: Mapped[str | None] = mapped_column(VARCHAR(255)) # type: ignore[assignment]
+ provider: Mapped[str | None] = mapped_column(VARCHAR(32)) # type: ignore[assignment]
+ extra_data: Mapped[dict[str, Any] | None] = mapped_column( # type: ignore[assignment, unused-ignore]
MutableJSONType
)
- lifetime: Mapped[Optional[int]]
- assoc_type: Mapped[Optional[str]] = mapped_column(VARCHAR(64))
+ lifetime: Mapped[int | None]
+ assoc_type: Mapped[str | None] = mapped_column(VARCHAR(64))
user: Mapped[Optional["User"]] = relationship( # type: ignore[assignment, unused-ignore]
back_populates="social_auth"
)
# This static property is set at: galaxy.authnz.psa_authnz.PSAAuthnz
- sa_session: ClassVar[Optional[Session]] = None
+ sa_session: ClassVar[Session | None] = None
def __init__(self, provider, uid, extra_data=None, lifetime=None, assoc_type=None, user=None):
self.provider = provider
@@ -11746,18 +11753,18 @@ class Page(Base, HasTags, RepresentById, UsesCreateAndUpdateTime):
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
user_id: Mapped[int] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- latest_revision_id: Mapped[Optional[int]] = mapped_column(
+ latest_revision_id: Mapped[int | None] = mapped_column(
ForeignKey("page_revision.id", use_alter=True, name="page_latest_revision_id_fk"), index=True
)
- title: Mapped[Optional[str]] = mapped_column(TEXT)
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- importable: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- slug: Mapped[Optional[str]] = mapped_column(TEXT)
- published: Mapped[Optional[bool]] = mapped_column(index=True, default=False)
- source_invocation_id: Mapped[Optional[int]] = mapped_column(
+ title: Mapped[str | None] = mapped_column(TEXT)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False)
+ importable: Mapped[bool | None] = mapped_column(index=True, default=False)
+ slug: Mapped[str | None] = mapped_column(TEXT)
+ published: Mapped[bool | None] = mapped_column(index=True, default=False)
+ source_invocation_id: Mapped[int | None] = mapped_column(
ForeignKey("workflow_invocation.id"), index=True, nullable=True
)
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True, nullable=True)
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True, nullable=True)
user: Mapped["User"] = relationship()
revisions: Mapped[list["PageRevision"]] = relationship(
cascade="all, delete-orphan",
@@ -11846,10 +11853,10 @@ class PageRevision(Base, Dictifiable, RepresentById):
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
page_id: Mapped[int] = mapped_column(ForeignKey("page.id"), index=True)
- title: Mapped[Optional[str]] = mapped_column(TEXT)
- content: Mapped[Optional[str]] = mapped_column(TEXT)
- content_format: Mapped[Optional[str]] = mapped_column(TrimmedString(32))
- edit_source: Mapped[Optional[str]] = mapped_column(TrimmedString(16), default=None)
+ title: Mapped[str | None] = mapped_column(TEXT)
+ content: Mapped[str | None] = mapped_column(TEXT)
+ content_format: Mapped[str | None] = mapped_column(TrimmedString(32))
+ edit_source: Mapped[str | None] = mapped_column(TrimmedString(16), default=None)
page: Mapped["Page"] = relationship(primaryjoin=(lambda: Page.id == PageRevision.page_id))
DEFAULT_CONTENT_FORMAT = "html"
dict_element_visible_keys = ["id", "page_id", "title", "content", "content_format", "edit_source"]
@@ -11885,17 +11892,17 @@ class Visualization(Base, HasTags, RepresentById, UsesCreateAndUpdateTime):
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
user_id: Mapped[int] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- latest_revision_id: Mapped[Optional[int]] = mapped_column(
+ latest_revision_id: Mapped[int | None] = mapped_column(
ForeignKey("visualization_revision.id", use_alter=True, name="visualization_latest_revision_id_fk"),
index=True,
)
- title: Mapped[Optional[str]] = mapped_column(TEXT)
- type: Mapped[Optional[str]] = mapped_column(TEXT)
- dbkey: Mapped[Optional[str]] = mapped_column(TEXT)
- deleted: Mapped[Optional[bool]] = mapped_column(default=False, index=True)
- importable: Mapped[Optional[bool]] = mapped_column(default=False, index=True)
- slug: Mapped[Optional[str]] = mapped_column(TEXT)
- published: Mapped[Optional[bool]] = mapped_column(default=False, index=True)
+ title: Mapped[str | None] = mapped_column(TEXT)
+ type: Mapped[str | None] = mapped_column(TEXT)
+ dbkey: Mapped[str | None] = mapped_column(TEXT)
+ deleted: Mapped[bool | None] = mapped_column(default=False, index=True)
+ importable: Mapped[bool | None] = mapped_column(default=False, index=True)
+ slug: Mapped[str | None] = mapped_column(TEXT)
+ published: Mapped[bool | None] = mapped_column(default=False, index=True)
user: Mapped["User"] = relationship()
revisions: Mapped[list["VisualizationRevision"]] = relationship(
@@ -11993,9 +12000,9 @@ class VisualizationRevision(Base, RepresentById):
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
visualization_id: Mapped[int] = mapped_column(ForeignKey("visualization.id"), index=True)
- title: Mapped[Optional[str]] = mapped_column(TEXT)
- dbkey: Mapped[Optional[str]] = mapped_column(TEXT)
- config: Mapped[Optional[bytes]] = mapped_column(MutableJSONType)
+ title: Mapped[str | None] = mapped_column(TEXT)
+ dbkey: Mapped[str | None] = mapped_column(TEXT)
+ config: Mapped[bytes | None] = mapped_column(MutableJSONType)
visualization: Mapped["Visualization"] = relationship(
back_populates="revisions",
primaryjoin=(lambda: Visualization.id == VisualizationRevision.visualization_id),
@@ -12028,9 +12035,9 @@ class Tag(Base, RepresentById):
__table_args__ = (UniqueConstraint("name"),)
id: Mapped[int] = mapped_column(primary_key=True)
- type: Mapped[Optional[int]]
- parent_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tag.id"))
- name: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
+ type: Mapped[int | None]
+ parent_id: Mapped[int | None] = mapped_column(ForeignKey("tag.id"))
+ name: Mapped[str | None] = mapped_column(TrimmedString(255))
children: Mapped[list["Tag"]] = relationship(back_populates="parent")
parent: Mapped[Optional["Tag"]] = relationship(back_populates="children", remote_side=[id])
@@ -12041,8 +12048,8 @@ class Tag(Base, RepresentById):
class ItemTagAssociation(Dictifiable):
dict_collection_visible_keys = ["id", "user_tname", "user_value"]
dict_element_visible_keys = dict_collection_visible_keys
- user_tname: Mapped[Optional[str]]
- user_value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_tname: Mapped[str | None]
+ user_value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
@@ -12065,9 +12072,9 @@ class HistoryTagAssociation(Base, ItemTagAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
history_id: Mapped[int] = mapped_column(ForeignKey("history.id"), index=True, nullable=True)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
history: Mapped["History"] = relationship(back_populates="tags")
tag: Mapped["Tag"] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -12081,9 +12088,9 @@ class HistoryDatasetAssociationTagAssociation(Base, ItemTagAssociation, Represen
ForeignKey("history_dataset_association.id"), index=True, nullable=True
)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
history_dataset_association: Mapped["HistoryDatasetAssociation"] = relationship(back_populates="tags")
tag: Mapped["Tag"] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -12097,9 +12104,9 @@ class LibraryDatasetDatasetAssociationTagAssociation(Base, ItemTagAssociation, R
ForeignKey("library_dataset_dataset_association.id"), index=True, nullable=True
)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
library_dataset_dataset_association: Mapped["LibraryDatasetDatasetAssociation"] = relationship(
back_populates="tags"
)
@@ -12113,9 +12120,9 @@ class PageTagAssociation(Base, ItemTagAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
page_id: Mapped[int] = mapped_column(ForeignKey("page.id"), index=True, nullable=True)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
page: Mapped["Page"] = relationship(back_populates="tags")
tag: Mapped["Tag"] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -12127,9 +12134,9 @@ class WorkflowStepTagAssociation(Base, ItemTagAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
workflow_step_id: Mapped[int] = mapped_column(ForeignKey("workflow_step.id"), index=True, nullable=True)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
workflow_step: Mapped["WorkflowStep"] = relationship(back_populates="tags")
tag: Mapped["Tag"] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -12141,9 +12148,9 @@ class StoredWorkflowTagAssociation(Base, ItemTagAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
stored_workflow_id: Mapped[int] = mapped_column(ForeignKey("stored_workflow.id"), index=True, nullable=True)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
stored_workflow: Mapped["StoredWorkflow"] = relationship(back_populates="tags")
tag: Mapped["Tag"] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -12155,9 +12162,9 @@ class VisualizationTagAssociation(Base, ItemTagAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
visualization_id: Mapped[int] = mapped_column(ForeignKey("visualization.id"), index=True, nullable=True)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
visualization: Mapped["Visualization"] = relationship(back_populates="tags")
tag: Mapped["Tag"] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -12171,9 +12178,9 @@ class HistoryDatasetCollectionTagAssociation(Base, ItemTagAssociation, Represent
ForeignKey("history_dataset_collection_association.id"), index=True, nullable=True
)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
dataset_collection: Mapped["HistoryDatasetCollectionAssociation"] = relationship(back_populates="tags")
tag: Mapped["Tag"] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -12187,9 +12194,9 @@ class LibraryDatasetCollectionTagAssociation(Base, ItemTagAssociation, Represent
ForeignKey("library_dataset_collection_association.id"), index=True, nullable=True
)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
dataset_collection: Mapped["LibraryDatasetCollectionAssociation"] = relationship(back_populates="tags")
tag: Mapped["Tag"] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -12201,9 +12208,9 @@ class ToolTagAssociation(Base, ItemTagAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
tool_id: Mapped[str] = mapped_column(TrimmedString(255), index=True, nullable=True)
tag_id: Mapped[int] = mapped_column(ForeignKey("tag.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- user_tname: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_tname: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ value: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
tag: Mapped["Tag"] = relationship()
user: Mapped[Optional["User"]] = relationship()
@@ -12215,7 +12222,7 @@ class HistoryAnnotationAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
history_id: Mapped[int] = mapped_column(ForeignKey("history.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
annotation: Mapped[str] = mapped_column(TEXT, nullable=True)
history: Mapped["History"] = relationship(back_populates="annotations")
user: Mapped["User"] = relationship()
@@ -12229,7 +12236,7 @@ class HistoryDatasetAssociationAnnotationAssociation(Base, RepresentById):
history_dataset_association_id: Mapped[int] = mapped_column(
ForeignKey("history_dataset_association.id"), index=True, nullable=True
)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
annotation: Mapped[str] = mapped_column(TEXT, nullable=True)
hda: Mapped["HistoryDatasetAssociation"] = relationship(back_populates="annotations")
user: Mapped[Optional["User"]] = relationship()
@@ -12241,7 +12248,7 @@ class StoredWorkflowAnnotationAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
stored_workflow_id: Mapped[int] = mapped_column(ForeignKey("stored_workflow.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
annotation: Mapped[str] = mapped_column(TEXT, nullable=True)
stored_workflow: Mapped["StoredWorkflow"] = relationship(back_populates="annotations")
user: Mapped[Optional["User"]] = relationship()
@@ -12253,7 +12260,7 @@ class WorkflowStepAnnotationAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
workflow_step_id: Mapped[int] = mapped_column(ForeignKey("workflow_step.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
annotation: Mapped[str] = mapped_column(TEXT, nullable=True)
workflow_step: Mapped["WorkflowStep"] = relationship(back_populates="annotations")
user: Mapped[Optional["User"]] = relationship()
@@ -12265,7 +12272,7 @@ class PageAnnotationAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
page_id: Mapped[int] = mapped_column(ForeignKey("page.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
annotation: Mapped[str] = mapped_column(TEXT, nullable=True)
page: Mapped["Page"] = relationship(back_populates="annotations")
user: Mapped[Optional["User"]] = relationship()
@@ -12277,7 +12284,7 @@ class VisualizationAnnotationAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
visualization_id: Mapped[int] = mapped_column(ForeignKey("visualization.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
annotation: Mapped[str] = mapped_column(TEXT, nullable=True)
visualization: Mapped["Visualization"] = relationship(back_populates="annotations")
user: Mapped[Optional["User"]] = relationship()
@@ -12290,7 +12297,7 @@ class HistoryDatasetCollectionAssociationAnnotationAssociation(Base, RepresentBy
history_dataset_collection_id: Mapped[int] = mapped_column(
ForeignKey("history_dataset_collection_association.id"), index=True, nullable=True
)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
annotation: Mapped[str] = mapped_column(TEXT, nullable=True)
history_dataset_collection: Mapped["HistoryDatasetCollectionAssociation"] = relationship(
back_populates="annotations"
@@ -12305,7 +12312,7 @@ class LibraryDatasetCollectionAnnotationAssociation(Base, RepresentById):
library_dataset_collection_id: Mapped[int] = mapped_column(
ForeignKey("library_dataset_collection_association.id"), index=True, nullable=True
)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
annotation: Mapped[str] = mapped_column(TEXT, nullable=True)
dataset_collection: Mapped["LibraryDatasetCollectionAssociation"] = relationship(back_populates="annotations")
user: Mapped[Optional["User"]] = relationship()
@@ -12315,10 +12322,10 @@ class Vault(Base):
__tablename__ = "vault"
key: Mapped[str] = mapped_column(Text, primary_key=True)
- parent_key: Mapped[Optional[str]] = mapped_column(Text, ForeignKey(key), index=True)
+ parent_key: Mapped[str | None] = mapped_column(Text, ForeignKey(key), index=True)
children: Mapped[list["Vault"]] = relationship(back_populates="parent")
parent: Mapped[Optional["Vault"]] = relationship(back_populates="children", remote_side=[key])
- value: Mapped[Optional[str]] = mapped_column(Text)
+ value: Mapped[str | None] = mapped_column(Text)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
@@ -12342,7 +12349,7 @@ class HistoryRatingAssociation(ItemRatingAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
history_id: Mapped[int] = mapped_column(ForeignKey("history.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
rating: Mapped[int] = mapped_column(index=True, nullable=True)
history: Mapped["History"] = relationship(back_populates="ratings")
user: Mapped[Optional["User"]] = relationship()
@@ -12359,7 +12366,7 @@ class HistoryDatasetAssociationRatingAssociation(ItemRatingAssociation, Represen
history_dataset_association_id: Mapped[int] = mapped_column(
ForeignKey("history_dataset_association.id"), index=True, nullable=True
)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
rating: Mapped[int] = mapped_column(index=True, nullable=True)
history_dataset_association: Mapped["HistoryDatasetAssociation"] = relationship(back_populates="ratings")
user: Mapped[Optional["User"]] = relationship()
@@ -12374,7 +12381,7 @@ class StoredWorkflowRatingAssociation(ItemRatingAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
stored_workflow_id: Mapped[int] = mapped_column(ForeignKey("stored_workflow.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
rating: Mapped[int] = mapped_column(index=True, nullable=True)
stored_workflow: Mapped["StoredWorkflow"] = relationship(back_populates="ratings")
user: Mapped[Optional["User"]] = relationship()
@@ -12389,7 +12396,7 @@ class PageRatingAssociation(ItemRatingAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
page_id: Mapped[int] = mapped_column(ForeignKey("page.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
rating: Mapped[int] = mapped_column(index=True, nullable=True)
page: Mapped["Page"] = relationship(back_populates="ratings")
user: Mapped[Optional["User"]] = relationship()
@@ -12404,7 +12411,7 @@ class VisualizationRatingAssociation(ItemRatingAssociation, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
visualization_id: Mapped[int] = mapped_column(ForeignKey("visualization.id"), index=True, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
rating: Mapped[int] = mapped_column(index=True, nullable=True)
visualization: Mapped["Visualization"] = relationship(back_populates="ratings")
user: Mapped[Optional["User"]] = relationship()
@@ -12421,7 +12428,7 @@ class HistoryDatasetCollectionRatingAssociation(ItemRatingAssociation, Represent
history_dataset_collection_id: Mapped[int] = mapped_column(
ForeignKey("history_dataset_collection_association.id"), index=True, nullable=True
)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
rating: Mapped[int] = mapped_column(index=True, nullable=True)
dataset_collection: Mapped["HistoryDatasetCollectionAssociation"] = relationship(back_populates="ratings")
user: Mapped[Optional["User"]] = relationship()
@@ -12438,7 +12445,7 @@ class LibraryDatasetCollectionRatingAssociation(ItemRatingAssociation, Represent
library_dataset_collection_id: Mapped[int] = mapped_column(
ForeignKey("library_dataset_collection_association.id"), index=True, nullable=True
)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
rating: Mapped[int] = mapped_column(index=True, nullable=True)
dataset_collection: Mapped["LibraryDatasetCollectionAssociation"] = relationship(back_populates="ratings")
user: Mapped[Optional["User"]] = relationship()
@@ -12455,8 +12462,8 @@ class DataManagerHistoryAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
- history_id: Mapped[Optional[int]] = mapped_column(ForeignKey("history.id"), index=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ history_id: Mapped[int | None] = mapped_column(ForeignKey("history.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
history: Mapped[Optional["History"]] = relationship()
user: Mapped[Optional["User"]] = relationship(back_populates="data_manager_histories")
@@ -12468,8 +12475,8 @@ class DataManagerJobAssociation(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
- job_id: Mapped[Optional[int]] = mapped_column(ForeignKey("job.id"), index=True)
- data_manager_id: Mapped[Optional[str]] = mapped_column(TEXT)
+ job_id: Mapped[int | None] = mapped_column(ForeignKey("job.id"), index=True)
+ data_manager_id: Mapped[str | None] = mapped_column(TEXT)
job: Mapped[Optional["Job"]] = relationship(back_populates="data_manager_association", uselist=False)
@@ -12477,9 +12484,9 @@ class UserPreference(Base, RepresentById):
__tablename__ = "user_preference"
id: Mapped[int] = mapped_column(primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- name: Mapped[Optional[str]] = mapped_column(Unicode(255), index=True)
- value: Mapped[Optional[str]] = mapped_column(Text)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ name: Mapped[str | None] = mapped_column(Unicode(255), index=True)
+ value: Mapped[str | None] = mapped_column(Text)
def __init__(self, name=None, value=None):
# Do not remove this constructor: it is set as the creator for the User.preferences
@@ -12495,12 +12502,12 @@ class UsesTemplatesAppConfig(Protocol):
class HasConfigSecrets(RepresentById):
secret_config_type: str
- template_secrets: Mapped[Optional[CONFIGURATION_TEMPLATE_CONFIGURATION_SECRET_NAMES_TYPE]]
- uuid: Mapped[Union[UUID, str]]
+ template_secrets: Mapped[CONFIGURATION_TEMPLATE_CONFIGURATION_SECRET_NAMES_TYPE | None]
+ uuid: Mapped[UUID | str]
user: Mapped["User"]
@classmethod
- def vault_key_from_uuid(clazz, uuid: Union[str, UUID], secret: str, app_config: UsesTemplatesAppConfig) -> str:
+ def vault_key_from_uuid(clazz, uuid: str | UUID, secret: str, app_config: UsesTemplatesAppConfig) -> str:
return f"{clazz.secret_config_type}/{str(get_uuid(uuid))}/{secret}"
def vault_id_prefix(self, app_config: UsesTemplatesAppConfig) -> str:
@@ -12515,7 +12522,7 @@ class HasConfigSecrets(RepresentById):
class HasConfigEnvironment(RepresentById):
- template_definition: Mapped[Optional[CONFIGURATION_TEMPLATE_DEFINITION_TYPE]]
+ template_definition: Mapped[CONFIGURATION_TEMPLATE_DEFINITION_TYPE | None]
@property
def template_environment(self) -> TemplateEnvironment:
@@ -12534,10 +12541,10 @@ T = TypeVar("T", bound=ConfigTemplate, covariant=True)
class HasConfigTemplate(HasConfigSecrets, HasConfigEnvironment, RepresentById, Generic[T]):
name: Mapped[str]
- description: Mapped[Optional[str]]
+ description: Mapped[str | None]
template_id: Mapped[str]
template_version: Mapped[int]
- template_variables: Mapped[Optional[CONFIGURATION_TEMPLATE_CONFIGURATION_VARIABLES_TYPE]]
+ template_variables: Mapped[CONFIGURATION_TEMPLATE_CONFIGURATION_VARIABLES_TYPE | None]
hidden: Mapped[bool]
active: Mapped[bool]
purged: Mapped[bool]
@@ -12552,14 +12559,14 @@ class UserObjectStore(Base, HasConfigTemplate):
secret_config_type = "object_store_config"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("galaxy_user.id"), index=True)
- uuid: Mapped[Union[UUID, str]] = mapped_column(UUIDType(), index=True)
+ user_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("galaxy_user.id"), index=True)
+ uuid: Mapped[UUID | str] = mapped_column(UUIDType(), index=True)
create_time: Mapped[datetime] = mapped_column(DateTime, default=now)
update_time: Mapped[datetime] = mapped_column(DateTime, default=now, onupdate=now, index=True)
# user specified name of the instance they've created
name: Mapped[str] = mapped_column(String(255), index=True)
# user specified description of the instance they've created
- description: Mapped[Optional[str]] = mapped_column(Text)
+ description: Mapped[str | None] = mapped_column(Text)
# active but doesn't appear in user selection
hidden: Mapped[bool] = mapped_column(default=False)
# set to False to deactive the source
@@ -12575,12 +12582,12 @@ class UserObjectStore(Base, HasConfigTemplate):
# the id/version and not record the definition... as the templates change
# over time this choice has some big consequences despite being easy to swap
# implementations.
- template_definition: Mapped[Optional[CONFIGURATION_TEMPLATE_DEFINITION_TYPE]] = mapped_column(JSONType)
+ template_definition: Mapped[CONFIGURATION_TEMPLATE_DEFINITION_TYPE | None] = mapped_column(JSONType)
# Big JSON blob of the variable name -> value mapping defined for the store's
# variables by the user.
- template_variables: Mapped[Optional[CONFIGURATION_TEMPLATE_CONFIGURATION_VARIABLES_TYPE]] = mapped_column(JSONType)
+ template_variables: Mapped[CONFIGURATION_TEMPLATE_CONFIGURATION_VARIABLES_TYPE | None] = mapped_column(JSONType)
# Track a list of secrets that were defined for this object store at creation
- template_secrets: Mapped[Optional[CONFIGURATION_TEMPLATE_CONFIGURATION_SECRET_NAMES_TYPE]] = mapped_column(JSONType)
+ template_secrets: Mapped[CONFIGURATION_TEMPLATE_CONFIGURATION_SECRET_NAMES_TYPE | None] = mapped_column(JSONType)
user: Mapped["User"] = relationship("User", back_populates="object_stores")
@@ -12589,7 +12596,7 @@ class UserObjectStore(Base, HasConfigTemplate):
return ObjectStoreTemplate(**self.template_definition or {})
def object_store_configuration(
- self, secrets: SecretsDict, environment: EnvironmentDict, templates: Optional[list[ObjectStoreTemplate]] = None
+ self, secrets: SecretsDict, environment: EnvironmentDict, templates: list[ObjectStoreTemplate] | None = None
) -> ObjectStoreConfiguration:
if templates is None:
templates = [self.template]
@@ -12620,14 +12627,14 @@ class UserFileSource(Base, HasConfigTemplate):
secret_config_type = "file_source_config"
id: Mapped[int] = mapped_column(primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- uuid: Mapped[Union[UUID, str]] = mapped_column(UUIDType(), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ uuid: Mapped[UUID | str] = mapped_column(UUIDType(), index=True)
create_time: Mapped[datetime] = mapped_column(default=now)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, index=True)
# user specified name of the instance they've created
name: Mapped[str] = mapped_column(String(255), index=True)
# user specified description of the instance they've created
- description: Mapped[Optional[str]] = mapped_column(Text)
+ description: Mapped[str | None] = mapped_column(Text)
# active but doesn't appear in user selection
hidden: Mapped[bool] = mapped_column(default=False)
# set to False to deactive the source
@@ -12643,12 +12650,12 @@ class UserFileSource(Base, HasConfigTemplate):
# the id/version and not record the definition... as the templates change
# over time this choice has some big consequences despite being easy to swap
# implementations.
- template_definition: Mapped[Optional[CONFIGURATION_TEMPLATE_DEFINITION_TYPE]] = mapped_column(JSONType)
+ template_definition: Mapped[CONFIGURATION_TEMPLATE_DEFINITION_TYPE | None] = mapped_column(JSONType)
# Big JSON blob of the variable name -> value mapping defined for the store's
# variables by the user.
- template_variables: Mapped[Optional[CONFIGURATION_TEMPLATE_CONFIGURATION_VARIABLES_TYPE]] = mapped_column(JSONType)
+ template_variables: Mapped[CONFIGURATION_TEMPLATE_CONFIGURATION_VARIABLES_TYPE | None] = mapped_column(JSONType)
# Track a list of secrets that were defined for this object store at creation
- template_secrets: Mapped[Optional[CONFIGURATION_TEMPLATE_CONFIGURATION_SECRET_NAMES_TYPE]] = mapped_column(JSONType)
+ template_secrets: Mapped[CONFIGURATION_TEMPLATE_CONFIGURATION_SECRET_NAMES_TYPE | None] = mapped_column(JSONType)
user: Mapped["User"] = relationship("User", back_populates="file_sources")
@@ -12661,7 +12668,7 @@ class UserFileSource(Base, HasConfigTemplate):
secrets: SecretsDict,
environment: EnvironmentDict,
implicit: ImplicitConfigurationParameters,
- templates: Optional[list[FileSourceTemplate]] = None,
+ templates: list[FileSourceTemplate] | None = None,
) -> FileSourceConfiguration:
if templates is None:
templates = [self.template]
@@ -12693,16 +12700,16 @@ class ToolLandingRequest(Base):
__tablename__ = "tool_landing_request"
id: Mapped[int] = mapped_column(primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- update_time: Mapped[Optional[datetime]] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
- uuid: Mapped[Union[UUID, str]] = mapped_column(UUIDType(), index=True)
+ update_time: Mapped[datetime | None] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
+ uuid: Mapped[UUID | str] = mapped_column(UUIDType(), index=True)
tool_id: Mapped[str] = mapped_column(String(255))
- tool_version: Mapped[Optional[str]] = mapped_column(String(255), default=None)
- request_state: Mapped[Optional[dict]] = mapped_column(JSONType)
- client_secret: Mapped[Optional[str]] = mapped_column(String(255), default=None)
+ tool_version: Mapped[str | None] = mapped_column(String(255), default=None)
+ request_state: Mapped[dict | None] = mapped_column(JSONType)
+ client_secret: Mapped[str | None] = mapped_column(String(255), default=None)
public: Mapped[bool] = mapped_column(Boolean)
- origin: Mapped[Optional[str]] = mapped_column(String(255), default=None)
+ origin: Mapped[str | None] = mapped_column(String(255), default=None)
user: Mapped[Optional["User"]] = relationship()
@@ -12712,23 +12719,23 @@ class WorkflowLandingRequest(Base):
__tablename__ = "workflow_landing_request"
id: Mapped[int] = mapped_column(primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- workflow_id: Mapped[Optional[int]] = mapped_column(ForeignKey("stored_workflow.id"), nullable=True)
- stored_workflow_id: Mapped[Optional[int]] = mapped_column(ForeignKey("workflow.id"), nullable=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ workflow_id: Mapped[int | None] = mapped_column(ForeignKey("stored_workflow.id"), nullable=True)
+ stored_workflow_id: Mapped[int | None] = mapped_column(ForeignKey("workflow.id"), nullable=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- update_time: Mapped[Optional[datetime]] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
- uuid: Mapped[Union[UUID, str]] = mapped_column(UUIDType(), index=True)
- request_state: Mapped[Optional[dict]] = mapped_column(JSONType)
- client_secret: Mapped[Optional[str]] = mapped_column(String(255), default=None)
- workflow_source: Mapped[Optional[str]] = mapped_column(String(255), default=None)
- workflow_source_type: Mapped[Optional[str]] = mapped_column(String(255), default=None)
+ update_time: Mapped[datetime | None] = mapped_column(index=True, default=now, onupdate=now, nullable=True)
+ uuid: Mapped[UUID | str] = mapped_column(UUIDType(), index=True)
+ request_state: Mapped[dict | None] = mapped_column(JSONType)
+ client_secret: Mapped[str | None] = mapped_column(String(255), default=None)
+ workflow_source: Mapped[str | None] = mapped_column(String(255), default=None)
+ workflow_source_type: Mapped[str | None] = mapped_column(String(255), default=None)
public: Mapped[bool] = mapped_column(Boolean)
user: Mapped[Optional["User"]] = relationship()
stored_workflow: Mapped[Optional["StoredWorkflow"]] = relationship()
workflow: Mapped[Optional["Workflow"]] = relationship()
- origin: Mapped[Optional[str]] = mapped_column(String(255), default=None)
+ origin: Mapped[str | None] = mapped_column(String(255), default=None)
class LandingRequestToWorkflowInvocationAssociation(Base, RepresentById):
@@ -12758,11 +12765,11 @@ class UserAction(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- session_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_session.id", ondelete="SET NULL"), index=True)
- action: Mapped[Optional[str]] = mapped_column(Unicode(255))
- context: Mapped[Optional[str]] = mapped_column(Unicode(512))
- params: Mapped[Optional[str]] = mapped_column(Unicode(1024))
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ session_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_session.id", ondelete="SET NULL"), index=True)
+ action: Mapped[str | None] = mapped_column(Unicode(255))
+ context: Mapped[str | None] = mapped_column(Unicode(512))
+ params: Mapped[str | None] = mapped_column(Unicode(1024))
user: Mapped[Optional["User"]] = relationship()
@@ -12771,8 +12778,8 @@ class APIKeys(Base, RepresentById):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- key: Mapped[Optional[str]] = mapped_column(TrimmedString(32), index=True, unique=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ key: Mapped[str | None] = mapped_column(TrimmedString(32), index=True, unique=True)
user: Mapped[Optional["User"]] = relationship(back_populates="api_keys")
deleted: Mapped[bool] = mapped_column(index=True, server_default=false())
@@ -12809,7 +12816,7 @@ class CleanupEvent(Base):
id: Mapped[int] = mapped_column(primary_key=True)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
- message: Mapped[Optional[str]] = mapped_column(TrimmedString(1024))
+ message: Mapped[str | None] = mapped_column(TrimmedString(1024))
class CleanupEventDatasetAssociation(Base):
@@ -12971,7 +12978,7 @@ class DatasetStorageOperationRun(Base):
state: Mapped[str] = mapped_column(String(32), index=True)
skip_ineligible: Mapped[bool] = mapped_column(Boolean, default=True)
notify_on_completion: Mapped[bool] = mapped_column(Boolean, default=True)
- task_id: Mapped[Optional[Union[UUID, str]]] = mapped_column(UUIDType(), index=True)
+ task_id: Mapped[UUID | str | None] = mapped_column(UUIDType(), index=True)
total_count: Mapped[int] = mapped_column(default=0)
succeeded_count: Mapped[int] = mapped_column(default=0)
failed_count: Mapped[int] = mapped_column(default=0)
@@ -12991,7 +12998,7 @@ class DatasetStorageOperationRunItem(Base):
run_id: Mapped[int] = mapped_column(ForeignKey("dataset_storage_operation_run.id", ondelete="CASCADE"), index=True)
dataset_id: Mapped[int] = mapped_column(ForeignKey("dataset.id", ondelete="CASCADE"), index=True)
state: Mapped[str] = mapped_column(String(32), index=True)
- reason_code: Mapped[Optional[str]] = mapped_column(String(64), nullable=True)
+ reason_code: Mapped[str | None] = mapped_column(String(64), nullable=True)
bytes_processed: Mapped[int] = mapped_column(default=0)
create_time: Mapped[datetime] = mapped_column(default=now, nullable=True)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now, nullable=True)
@@ -13012,7 +13019,7 @@ class UserCredentials(Base):
source_version: Mapped[str] = mapped_column()
name: Mapped[str] = mapped_column()
version: Mapped[str] = mapped_column()
- current_group_id: Mapped[Optional[int]] = mapped_column(
+ current_group_id: Mapped[int | None] = mapped_column(
ForeignKey("credentials_group.id", ondelete="CASCADE"), index=True, nullable=True
)
create_time: Mapped[datetime] = mapped_column(default=now)
@@ -13045,7 +13052,7 @@ class Credential(Base):
name: Mapped[str] = mapped_column()
is_secret: Mapped[bool] = mapped_column(Boolean)
is_set: Mapped[bool] = mapped_column(Boolean)
- value: Mapped[Optional[str]] = mapped_column(nullable=True)
+ value: Mapped[str | None] = mapped_column(nullable=True)
create_time: Mapped[datetime] = mapped_column(default=now)
update_time: Mapped[datetime] = mapped_column(default=now, onupdate=now)
@@ -13398,7 +13405,9 @@ def receive_init(target, args, kwargs):
return # Once is enough.
-JobStateSummary = NamedTuple("JobStateSummary", [(value, int) for value in enum_values(Job.states)] + [("all_jobs", int)]) # type: ignore[misc] # Ref https://github.com/python/mypy/issues/848#issuecomment-255237167
+JobStateSummary = NamedTuple( # type: ignore[misc] # Ref https://github.com/python/mypy/issues/848#issuecomment-255237167
+ "JobStateSummary", [(value, int) for value in enum_values(Job.states)] + [("all_jobs", int)]
+)
_ZERO_JOB_STATE_SUMMARY = JobStateSummary._make([0] * (len(Job.states) + 1))
diff --git a/lib/galaxy/model/base.py b/lib/galaxy/model/base.py
index a0720e4c784..001632f1612 100644
--- a/lib/galaxy/model/base.py
+++ b/lib/galaxy/model/base.py
@@ -14,7 +14,6 @@ from inspect import (
from types import ModuleType
from typing import (
TYPE_CHECKING,
- Union,
)
from sqlalchemy import event
@@ -48,7 +47,7 @@ log = logging.getLogger(__name__)
# of a request (which run within a threadpool) to see changes to the ContextVar
# state. See https://github.com/tiangolo/fastapi/issues/953#issuecomment-586006249
# for details
-REQUEST_ID: ContextVar[Union[dict[str, str], None]] = ContextVar("request_id", default=None)
+REQUEST_ID: ContextVar[dict[str, str] | None] = ContextVar("request_id", default=None)
def check_database_connection(session):
@@ -142,10 +141,10 @@ class SharedModelMapping(ModelMapping):
a way to do app.model. for common code shared by the tool shed and Galaxy.
"""
- User: Union[type["GalaxyUser"], type["ToolShedUser"]]
- GalaxySession: Union[type["GalaxyGalaxySession"], type["ToolShedGalaxySession"]]
- APIKeys: Union[type["GalaxyAPIKeys"], type["ToolShedAPIKeys"]]
- PasswordResetToken: Union[type["GalaxyPasswordResetToken"], type["ToolShedPasswordResetToken"]]
+ User: type["GalaxyUser"] | type["ToolShedUser"]
+ GalaxySession: type["GalaxyGalaxySession"] | type["ToolShedGalaxySession"]
+ APIKeys: type["GalaxyAPIKeys"] | type["ToolShedAPIKeys"]
+ PasswordResetToken: type["GalaxyPasswordResetToken"] | type["ToolShedPasswordResetToken"]
def versioned_objects(iter):
diff --git a/lib/galaxy/model/custom_types.py b/lib/galaxy/model/custom_types.py
index 0403c9d236f..d28c078a5b7 100644
--- a/lib/galaxy/model/custom_types.py
+++ b/lib/galaxy/model/custom_types.py
@@ -6,7 +6,6 @@ import uuid
from collections import deque
from itertools import chain
from sys import getsizeof
-from typing import Optional
import numpy
import sqlalchemy
@@ -44,7 +43,7 @@ json_encoder = SafeJsonEncoder(sort_keys=True)
json_decoder = json.JSONDecoder()
# Galaxy app will set this if configured to avoid circular dependency
-MAX_METADATA_VALUE_SIZE: Optional[int] = None
+MAX_METADATA_VALUE_SIZE: int | None = None
def _sniffnfix_pg9_hex(value):
diff --git a/lib/galaxy/model/database_object_names.py b/lib/galaxy/model/database_object_names.py
index 928f8c64d0d..2f7e058a717 100644
--- a/lib/galaxy/model/database_object_names.py
+++ b/lib/galaxy/model/database_object_names.py
@@ -3,10 +3,6 @@ Naming convention and helper functions for generating names of database
constraints and indexes.
"""
-from typing import (
- Union,
-)
-
from galaxy.util import listify
# Naming convention applied to database constraints and indexes.
@@ -21,12 +17,12 @@ NAMING_CONVENTION = {
}
-def build_foreign_key_name(table_name: str, column_names: Union[str, list]) -> str:
+def build_foreign_key_name(table_name: str, column_names: str | list) -> str:
columns = _as_str(column_names)
return f"{table_name}_{columns}_fkey"
-def build_unique_constraint_name(table_name: str, column_names: Union[str, list]) -> str:
+def build_unique_constraint_name(table_name: str, column_names: str | list) -> str:
columns = _as_str(column_names)
return f"{table_name}_{columns}_key"
@@ -35,10 +31,10 @@ def build_check_constraint_name(table_name: str, column_name: str) -> str:
return f"{table_name}_{column_name}_check"
-def build_index_name(table_name: str, column_names: Union[str, list]) -> str:
+def build_index_name(table_name: str, column_names: str | list) -> str:
columns = _as_str(column_names)
return f"ix_{table_name}_{columns}"
-def _as_str(column_names: Union[str, list]) -> str:
+def _as_str(column_names: str | list) -> str:
return "_".join(listify(column_names))
diff --git a/lib/galaxy/model/database_utils.py b/lib/galaxy/model/database_utils.py
index fa1cdea0f54..5e456683298 100644
--- a/lib/galaxy/model/database_utils.py
+++ b/lib/galaxy/model/database_utils.py
@@ -3,7 +3,6 @@ from contextlib import contextmanager
from functools import lru_cache
from typing import (
NewType,
- Optional,
)
from sqlalchemy import create_engine
@@ -132,7 +131,7 @@ class MySQLDatabaseManager(DatabaseManager):
conn.execute(stmt)
-def is_one_database(db1_url: str, db2_url: Optional[str]):
+def is_one_database(db1_url: str, db2_url: str | None):
"""
Check if the arguments refer to one database. This will be true
if only one argument is passed, or if the urls are the same.
diff --git a/lib/galaxy/model/dataset_collections/adapters.py b/lib/galaxy/model/dataset_collections/adapters.py
index bb847c889b9..a199e69db05 100644
--- a/lib/galaxy/model/dataset_collections/adapters.py
+++ b/lib/galaxy/model/dataset_collections/adapters.py
@@ -136,7 +136,6 @@ class PromoteCollectionElementToCollectionAdapter(DCECollectionAdapter):
class PromoteDatasetToCollection(CollectionAdapter):
-
def __init__(self, hda: "HistoryDatasetAssociation", collection_type: str):
assert collection_type in ["list", "paired_or_unpaired"]
self._hda = hda
diff --git a/lib/galaxy/model/dataset_collections/auto_identifiers.py b/lib/galaxy/model/dataset_collections/auto_identifiers.py
index e0fc26d3799..1fffa07e12a 100644
--- a/lib/galaxy/model/dataset_collections/auto_identifiers.py
+++ b/lib/galaxy/model/dataset_collections/auto_identifiers.py
@@ -1,9 +1,6 @@
"""Code around assigning implicit list identifiers for collections."""
import os.path
-from typing import (
- Optional,
-)
from urllib.parse import urlparse
from pydantic import BaseModel
@@ -26,13 +23,13 @@ def filename_to_element_identifier(filename_or_uri: str):
def fill_in_identifiers(
- uris_to_identifiers: list[tuple[str, Optional[str]]], config: Optional[FillIdentifiers]
-) -> list[Optional[str]]:
+ uris_to_identifiers: list[tuple[str, str | None]], config: FillIdentifiers | None
+) -> list[str | None]:
if config is None:
config = FillIdentifiers()
- new_identifiers: list[Optional[str]] = []
- seen_identifiers: set[Optional[str]] = set()
+ new_identifiers: list[str | None] = []
+ seen_identifiers: set[str | None] = set()
for uri, identifier in uris_to_identifiers:
if identifier is None and config.fill_inner_list_identifiers:
basename = filename_to_element_identifier(uri)
diff --git a/lib/galaxy/model/dataset_collections/auto_pairing.py b/lib/galaxy/model/dataset_collections/auto_pairing.py
index 7433bb07e3d..83cfe9dad1a 100644
--- a/lib/galaxy/model/dataset_collections/auto_pairing.py
+++ b/lib/galaxy/model/dataset_collections/auto_pairing.py
@@ -2,7 +2,6 @@ import re
from dataclasses import dataclass
from typing import (
Generic,
- Optional,
Protocol,
TypeVar,
)
@@ -25,7 +24,7 @@ COMMON_FILTERS: dict[str, tuple[str, str]] = {
}
-def paired_element_list_identifier(forward: str, reverse: str) -> Optional[str]:
+def paired_element_list_identifier(forward: str, reverse: str) -> str | None:
for forward_filter, reverse_filter in COMMON_FILTERS.values():
if forward_filter in forward and reverse_filter in reverse:
forward_base = filename_to_element_identifier(re.sub(f"{forward_filter}", "", forward))
@@ -60,8 +59,8 @@ class Pair(Generic[T]):
@dataclass
class PartialPair(Generic[T]):
name: str
- forward: Optional[T]
- reverse: Optional[T]
+ forward: T | None
+ reverse: T | None
def to_pair(self) -> Pair[T]:
assert self.forward
@@ -113,7 +112,7 @@ def auto_pair(elements: list[T]) -> AutoPairResponse[T]:
return AutoPairResponse(paired=[], unpaired=elements)
-def guess_initial_filter_type(elements: list[T]) -> Optional[str]:
+def guess_initial_filter_type(elements: list[T]) -> str | None:
illumina = 0
dot12s = 0
Rs = 0
diff --git a/lib/galaxy/model/dataset_collections/builder.py b/lib/galaxy/model/dataset_collections/builder.py
index 37e16c2a63b..a2a66f14777 100644
--- a/lib/galaxy/model/dataset_collections/builder.py
+++ b/lib/galaxy/model/dataset_collections/builder.py
@@ -27,11 +27,11 @@ if TYPE_CHECKING:
def build_collection(
type: "BaseDatasetCollectionType",
dataset_instances: "DatasetInstanceMapping",
- collection: Optional[DatasetCollection] = None,
- associated_identifiers: Optional[set[str]] = None,
- fields: Optional[Union[str, list["FieldDict"]]] = None,
+ collection: DatasetCollection | None = None,
+ associated_identifiers: set[str] | None = None,
+ fields: str | list["FieldDict"] | None = None,
column_definitions=None,
- rows: Optional[dict[str, Optional["SampleSheetRow"]]] = None,
+ rows: dict[str, Optional["SampleSheetRow"]] | None = None,
):
"""
Build DatasetCollection with populated DatasetcollectionElement objects
@@ -51,8 +51,8 @@ def set_collection_elements(
type: "BaseDatasetCollectionType",
dataset_instances: "DatasetInstanceMapping",
associated_identifiers: set[str],
- fields: Optional[Union[str, list["FieldDict"]]] = None,
- rows: Optional[dict[str, Optional["SampleSheetRow"]]] = None,
+ fields: str | list["FieldDict"] | None = None,
+ rows: dict[str, Optional["SampleSheetRow"]] | None = None,
) -> DatasetCollection:
new_element_keys = OrderedSet(dataset_instances.keys()) - associated_identifiers
new_dataset_instances = {k: dataset_instances[k] for k in new_element_keys}
@@ -104,7 +104,7 @@ class CollectionBuilder:
self._current_row_data = {}
# Store collection here so we don't recreate the collection all the time
- self.collection: Optional[DatasetCollection] = None
+ self.collection: DatasetCollection | None = None
self.associated_identifiers: set[str] = set()
def replace_elements_in_collection(
@@ -174,7 +174,7 @@ class CollectionBuilder:
def build_elements_and_rows(
self,
- ) -> tuple["DatasetInstanceMapping", Optional[dict[str, Optional["SampleSheetRow"]]]]:
+ ) -> tuple["DatasetInstanceMapping", dict[str, Optional["SampleSheetRow"]] | None]:
row_data = self._current_row_data
self._current_row_data = {}
return self.build_elements(), row_data
diff --git a/lib/galaxy/model/dataset_collections/query.py b/lib/galaxy/model/dataset_collections/query.py
index 1e559eff573..5918e02855c 100644
--- a/lib/galaxy/model/dataset_collections/query.py
+++ b/lib/galaxy/model/dataset_collections/query.py
@@ -1,7 +1,4 @@
import logging
-from typing import (
- Optional,
-)
from typing_extensions import Protocol
@@ -18,9 +15,8 @@ class HdcaLike(Protocol):
class DataCollectionParameterLike(Protocol):
-
@property
- def collection_types(self) -> Optional[list[str]]:
+ def collection_types(self) -> list[str] | None:
"""Return a list of collection type strings the parameter accepts."""
@@ -38,7 +34,7 @@ class HistoryQuery:
return HistoryQuery(**kwargs)
@staticmethod
- def from_collection_types(collection_types: Optional[list[str]], collection_type_descriptions):
+ def from_collection_types(collection_types: list[str] | None, collection_type_descriptions):
if collection_types:
collection_type_descriptions = [
collection_type_descriptions.for_collection_type(t) for t in collection_types
diff --git a/lib/galaxy/model/dataset_collections/rule_target_columns.py b/lib/galaxy/model/dataset_collections/rule_target_columns.py
index 0737ae27555..085d6ba976a 100644
--- a/lib/galaxy/model/dataset_collections/rule_target_columns.py
+++ b/lib/galaxy/model/dataset_collections/rule_target_columns.py
@@ -1,8 +1,5 @@
import re
from dataclasses import dataclass
-from typing import (
- Optional,
-)
from pydantic import BaseModel
@@ -56,7 +53,7 @@ COLUMN_TITLE_PREFIXES: dict[str, RuleBuilderMappingTargetKey] = {
}
-def column_title_to_target_type(column_title: str) -> Optional[RuleBuilderMappingTargetKey]:
+def column_title_to_target_type(column_title: str) -> RuleBuilderMappingTargetKey | None:
normalized_title = re.sub(r"[\s\(\)\-\_]|optional", "", column_title.lower())
if normalized_title not in COLUMN_TITLE_PREFIXES:
for key in COLUMN_TITLE_PREFIXES.keys():
@@ -142,7 +139,7 @@ def column_titles_to_headers(
inferred_columns: list[InferredColumnMapping] = []
for column_index, column_title in enumerate(column_titles):
- column_type_: Optional[RuleBuilderMappingTargetKey] = column_title_to_target_type(column_title)
+ column_type_: RuleBuilderMappingTargetKey | None = column_title_to_target_type(column_title)
if not column_type_:
# make a note in parse log that this column was skipped
continue
diff --git a/lib/galaxy/model/dataset_collections/rule_target_models.py b/lib/galaxy/model/dataset_collections/rule_target_models.py
index bee11f31289..2e746644ddd 100644
--- a/lib/galaxy/model/dataset_collections/rule_target_models.py
+++ b/lib/galaxy/model/dataset_collections/rule_target_models.py
@@ -1,6 +1,5 @@
from typing import (
Literal,
- Optional,
)
import yaml
@@ -23,17 +22,17 @@ RuleBuilderModes = Literal[
class ColumnTarget(BaseModel):
label: str
- help: Optional[str]
- modes: Optional[list[RuleBuilderModes]] = None
- importType: Optional[RuleBuilderImportType] = None
- multiple: Optional[bool] = False
- columnHeader: Optional[str] = None
- advanced: Optional[bool] = False
- requiresFtp: Optional[bool] = False
- example_column_names: Optional[list[str]] = None
+ help: str | None
+ modes: list[RuleBuilderModes] | None = None
+ importType: RuleBuilderImportType | None = None
+ multiple: bool | None = False
+ columnHeader: str | None = None
+ advanced: bool | None = False
+ requiresFtp: bool | None = False
+ example_column_names: list[str] | None = None
@property
- def example_column_names_as_str(self) -> Optional[str]:
+ def example_column_names_as_str(self) -> str | None:
if self.example_column_names:
return '"' + '", "'.join(self.example_column_names) + '"'
return ""
diff --git a/lib/galaxy/model/dataset_collections/structure.py b/lib/galaxy/model/dataset_collections/structure.py
index a4cf1e5a3d2..e4d40d60c4e 100644
--- a/lib/galaxy/model/dataset_collections/structure.py
+++ b/lib/galaxy/model/dataset_collections/structure.py
@@ -1,9 +1,8 @@
"""Module for reasoning about structure of and matching hierarchical collections of data."""
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
+ TypeAlias,
)
from galaxy.model import DatasetCollectionElement
@@ -15,7 +14,7 @@ if TYPE_CHECKING:
)
from .type_description import CollectionTypeDescription
- CollectionLike = Union[DatasetCollectionElement, "HistoryDatasetCollectionAssociation"]
+ CollectionLike: TypeAlias = DatasetCollectionElement | HistoryDatasetCollectionAssociation
class Leaf:
@@ -261,7 +260,7 @@ def get_collection(
def get_structure(
collection: "DatasetCollection",
collection_type_description: "CollectionTypeDescription",
- leaf_subcollection_type: Optional[str] = None,
+ leaf_subcollection_type: str | None = None,
):
"""Build a Tree (or UninitializedTree) describing a collection's shape.
diff --git a/lib/galaxy/model/dataset_collections/type_description.py b/lib/galaxy/model/dataset_collections/type_description.py
index d233fb61428..1fbcd3f2722 100644
--- a/lib/galaxy/model/dataset_collections/type_description.py
+++ b/lib/galaxy/model/dataset_collections/type_description.py
@@ -24,7 +24,6 @@ lattice diagram and worked examples.
import re
from typing import (
- Optional,
TYPE_CHECKING,
Union,
)
@@ -47,7 +46,7 @@ class CollectionTypeDescriptionFactory:
# I think.
self.type_registry = type_registry
- def for_collection_type(self, collection_type, fields: Optional[Union[str, list["FieldDict"]]] = None):
+ def for_collection_type(self, collection_type, fields: str | list["FieldDict"] | None = None):
assert collection_type is not None
return CollectionTypeDescription(collection_type, self, fields=fields)
@@ -63,7 +62,7 @@ class CollectionTypeDescription:
self,
collection_type: Union[str, "CollectionTypeDescription"],
collection_type_description_factory: CollectionTypeDescriptionFactory,
- fields: Optional[Union[str, list["FieldDict"]]] = None,
+ fields: str | list["FieldDict"] | None = None,
):
if isinstance(collection_type, CollectionTypeDescription):
self.collection_type = collection_type.collection_type
diff --git a/lib/galaxy/model/dataset_collections/types/sample_sheet.py b/lib/galaxy/model/dataset_collections/types/sample_sheet.py
index 987a269796d..5d3c1dd9902 100644
--- a/lib/galaxy/model/dataset_collections/types/sample_sheet.py
+++ b/lib/galaxy/model/dataset_collections/types/sample_sheet.py
@@ -1,6 +1,5 @@
from typing import (
cast,
- Optional,
)
from galaxy.exceptions import RequestParameterMissingException
@@ -16,7 +15,7 @@ class SampleSheetDatasetCollectionType(BaseDatasetCollectionType):
collection_type = "sample_sheet"
def generate_elements(self, dataset_instances, **kwds):
- rows = cast(Optional[dict[str, Optional[SampleSheetRow]]], kwds.get("rows", None))
+ rows = cast(dict[str, SampleSheetRow | None] | None, kwds.get("rows", None))
column_definitions = kwds.get("column_definitions", None)
if not column_definitions:
rows = rows if rows is not None else dict.fromkeys(dataset_instances)
diff --git a/lib/galaxy/model/dataset_collections/types/sample_sheet_util.py b/lib/galaxy/model/dataset_collections/types/sample_sheet_util.py
index 8cb7d5d5fdd..4ecedda9253 100644
--- a/lib/galaxy/model/dataset_collections/types/sample_sheet_util.py
+++ b/lib/galaxy/model/dataset_collections/types/sample_sheet_util.py
@@ -1,8 +1,4 @@
import re
-from typing import (
- Optional,
- Union,
-)
from pydantic import (
BaseModel,
@@ -25,19 +21,19 @@ from galaxy.tool_util_models.sample_sheet import (
from galaxy.util import strip_control_characters
SampleSheetRows = dict[str, SampleSheetRow]
-OptionalSampleSheetRows = Optional[SampleSheetRows]
+OptionalSampleSheetRows = SampleSheetRows | None
class SampleSheetColumnDefinitionModel(BaseModel):
model_config = ConfigDict(extra="forbid", strict=True)
name: str
type: SampleSheetColumnType
- description: Optional[str] = None
+ description: str | None = None
optional: bool
- validators: Optional[list[AnySafeValidatorModel]] = None
- restrictions: Optional[list[SampleSheetColumnValueT]] = None
- suggestions: Optional[list[SampleSheetColumnValueT]] = None
- default_value: Optional[SampleSheetColumnValueT] = None
+ validators: list[AnySafeValidatorModel] | None = None
+ restrictions: list[SampleSheetColumnValueT] | None = None
+ suggestions: list[SampleSheetColumnValueT] | None = None
+ default_value: SampleSheetColumnValueT | None = None
@model_validator(mode="after")
def check_nature_of_default(self) -> Self:
@@ -64,7 +60,7 @@ class SampleSheetColumnDefinitionModel(BaseModel):
SampleSheetColumnDefinitionsModel = RootModel[list[SampleSheetColumnDefinitionModel]]
-SampleSheetColumnDefinitionDictOrModel = Union[SampleSheetColumnDefinition, SampleSheetColumnDefinitionModel]
+SampleSheetColumnDefinitionDictOrModel = SampleSheetColumnDefinition | SampleSheetColumnDefinitionModel
def sample_sheet_column_definition_to_model(
@@ -76,7 +72,7 @@ def sample_sheet_column_definition_to_model(
return SampleSheetColumnDefinitionModel.model_validate(column_definition)
-def validate_column_definitions(column_definitions: Optional[SampleSheetColumnDefinitions]):
+def validate_column_definitions(column_definitions: SampleSheetColumnDefinitions | None):
for column_definition in column_definitions or []:
_validate_column_definition(column_definition)
@@ -95,8 +91,8 @@ def _validate_column_definition(column_definition: SampleSheetColumnDefinition):
def validate_row(
- row: Optional[SampleSheetRow],
- column_definitions: Optional[SampleSheetColumnDefinitions],
+ row: SampleSheetRow | None,
+ column_definitions: SampleSheetColumnDefinitions | None,
element_identifiers: list[str],
):
if not column_definitions:
@@ -175,8 +171,8 @@ def validate_column_value(
def column_definitions_compatible(
- collection_columns: Optional[SampleSheetColumnDefinitions],
- required_columns: Optional[SampleSheetColumnDefinitions],
+ collection_columns: SampleSheetColumnDefinitions | None,
+ required_columns: SampleSheetColumnDefinitions | None,
) -> bool:
"""Check if collection's column definitions exactly match required column definitions.
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 7bd15bd9b76..18a84d078ed 100644
--- a/lib/galaxy/model/dataset_collections/types/sample_sheet_workbook.py
+++ b/lib/galaxy/model/dataset_collections/types/sample_sheet_workbook.py
@@ -2,7 +2,6 @@ from dataclasses import dataclass
from typing import (
cast,
Literal,
- Optional,
Protocol,
TYPE_CHECKING,
Union,
@@ -102,7 +101,7 @@ WorkbookContentField: Base64StringT = Field(
title="Workbook Content (Base 64 encoded)",
description="The workbook content (the contents of the xlsx file) that have been base64 encoded.",
)
-PrefixRowsField: Optional[PrefixRowValuesT] = Field(
+PrefixRowsField: PrefixRowValuesT | None = Field(
None,
title="Prefix sample sheet values",
description="An area to pre-populate URIs, etc...",
@@ -115,7 +114,7 @@ SampleSheetCollectionType = Literal[
ParsedRow = dict[str, SampleSheetColumnValueT]
ParsedRows = list[ParsedRow]
-AnyLogMessage = Union[InferredColumnMapping, ContentTypeMessage, CsvDialectInferenceMessage]
+AnyLogMessage = InferredColumnMapping | ContentTypeMessage | CsvDialectInferenceMessage
SampleSheetParseLog = list[AnyLogMessage]
@@ -134,7 +133,7 @@ class CreateWorkbookRequest(BaseModel):
collection_type: SampleSheetCollectionType
prefix_columns_type: Literal["URI"] = "URI"
column_definitions: list[SampleSheetColumnDefinitionModel] = ColumnDefinitionsField
- prefix_values: Optional[PrefixRowValuesT] = None
+ prefix_values: PrefixRowValuesT | None = None
@dataclass
@@ -149,7 +148,7 @@ class CreateWorkbook(BaseModel):
collection_type: SampleSheetCollectionType
prefix_columns_type: Literal["URI", "ModelObjects"] = "URI"
column_definitions: list[SampleSheetColumnDefinitionModel] = ColumnDefinitionsField
- prefix_values: Optional[InternalPrefixRowValuesT] = None
+ prefix_values: InternalPrefixRowValuesT | None = None
@dataclass
@@ -173,7 +172,7 @@ class ParseWorkbookForCollection:
content: str = WorkbookContentField
-AnyParseWorkbook = Union[ParseWorkbook, ParseWorkbookForCollection]
+AnyParseWorkbook = ParseWorkbook | ParseWorkbookForCollection
INSTRUCTIONS = [
@@ -359,7 +358,7 @@ def generate_workbook(payload: CreateWorkbook) -> Workbook:
freeze_header_row(worksheet)
for index, column_definition in enumerate(column_definitions):
- validation: Optional[DataValidation] = None
+ validation: DataValidation | None = None
if column_definition.type == "int":
validation = DataValidation(type="whole", allow_blank=True)
# TODO: operator="between", formula1="1", formula2="1000"
@@ -469,7 +468,7 @@ class FetchPrefixColumn:
return HasHelp(title=self.title, help=self.title)
-def prefix_columns(payload: Union[CreateWorkbook, AnyParseWorkbook]) -> list[FetchPrefixColumn]:
+def prefix_columns(payload: CreateWorkbook | AnyParseWorkbook) -> list[FetchPrefixColumn]:
if isinstance(payload, (CreateWorkbook, ParseWorkbook)):
collection_type = payload.collection_type
columns_type = payload.prefix_columns_type
@@ -516,7 +515,7 @@ def prefix_columns(payload: Union[CreateWorkbook, AnyParseWorkbook]) -> list[Fet
return columns
-def prefix_column_names(payload: Union[CreateWorkbook, AnyParseWorkbook]) -> list[str]:
+def prefix_column_names(payload: CreateWorkbook | AnyParseWorkbook) -> list[str]:
return [c.title for c in prefix_columns(payload)]
diff --git a/lib/galaxy/model/dataset_collections/types/semantics.py b/lib/galaxy/model/dataset_collections/types/semantics.py
index 5e42b02894e..c449eb5b99c 100644
--- a/lib/galaxy/model/dataset_collections/types/semantics.py
+++ b/lib/galaxy/model/dataset_collections/types/semantics.py
@@ -13,8 +13,6 @@ from typing import (
Any,
Literal,
NamedTuple,
- Optional,
- Union,
)
import yaml
@@ -44,20 +42,20 @@ class ToolRuntimeFramework(BaseModel):
tool: str
-ToolRuntimeTest = Union[ToolRuntimeApi, ToolRuntimeFramework]
+ToolRuntimeTest = ToolRuntimeApi | ToolRuntimeFramework
class WorkflowRuntimeTest(BaseModel):
- api_test: Optional[str] = None
- framework_test: Optional[str] = None
+ api_test: str | None = None
+ framework_test: str | None = None
class ExampleTests(BaseModel):
model_config = ConfigDict(extra="forbid")
- tool_runtime: Optional[ToolRuntimeTest] = None
- workflow_runtime: Optional[WorkflowRuntimeTest] = None
- workflow_editor: Optional[str] = None
+ tool_runtime: ToolRuntimeTest | None = None
+ workflow_runtime: WorkflowRuntimeTest | None = None
+ workflow_editor: str | None = None
class DatasetsDeclaration(BaseModel):
@@ -112,7 +110,7 @@ class CollectionDeclarations(BaseModel):
collections: dict[str, CollectionDefinition]
-Expression = Union[str, DatasetsDeclaration, ToolDeclaration, CollectionDeclarations]
+Expression = str | DatasetsDeclaration | ToolDeclaration | CollectionDeclarations
# --- Structured Then Expression Models ---
@@ -170,7 +168,7 @@ class DatasetInput(BaseModel):
class MapOverInput(BaseModel):
type: Literal["map_over"]
collection: str
- sub_collection_type: Optional[str] = None
+ sub_collection_type: str | None = None
def as_latex(self) -> str:
if self.sub_collection_type:
@@ -195,9 +193,7 @@ class DatasetListInput(BaseModel):
return "[" + ",".join(self.refs) + "]"
-InputBinding = Annotated[
- Union[DatasetInput, MapOverInput, CollectionInput, DatasetListInput], Field(discriminator="type")
-]
+InputBinding = Annotated[DatasetInput | MapOverInput | CollectionInput | DatasetListInput, Field(discriminator="type")]
class ToolInvocation(BaseModel):
@@ -239,9 +235,7 @@ class NestedElements(BaseModel):
return _output_elements_to_latex(self.elements)
-OutputBinding = Annotated[
- Union[DatasetOutput, EllipsisMarker, ToolOutputRef, NestedElements], Field(discriminator="type")
-]
+OutputBinding = Annotated[DatasetOutput | EllipsisMarker | ToolOutputRef | NestedElements, Field(discriminator="type")]
NestedElements.model_rebuild()
@@ -256,7 +250,7 @@ class CollectionOutput(BaseModel):
return f"\\text{{collection}}<{ct},{el}>"
-OutputSpec = Annotated[Union[DatasetOutput, CollectionOutput], Field(discriminator="type")]
+OutputSpec = Annotated[DatasetOutput | CollectionOutput, Field(discriminator="type")]
class MapOverThen(BaseModel):
@@ -294,22 +288,22 @@ class InvalidThen(BaseModel):
return self.invocation.as_latex()
-ThenExpression = Annotated[Union[MapOverThen, ReductionThen, EquivalenceThen, InvalidThen], Field(discriminator="type")]
+ThenExpression = Annotated[MapOverThen | ReductionThen | EquivalenceThen | InvalidThen, Field(discriminator="type")]
class Example(BaseModel):
label: str
- assumptions: Optional[list[Expression]] = None
- then: Optional[ThenExpression] = None
+ assumptions: list[Expression] | None = None
+ then: ThenExpression | None = None
is_valid: bool = True
- tests: Optional[ExampleTests] = None
+ tests: ExampleTests | None = None
class ExampleEntry(BaseModel):
example: Example
-YAMLRootModel = RootModel[list[Union[DocEntry, ExampleEntry]]]
+YAMLRootModel = RootModel[list[DocEntry | ExampleEntry]]
WORDS_TO_TEXTIFY = ["list", "forward", "reverse", "mapOver", "collection", "dataset", "inner"]
@@ -346,7 +340,7 @@ def expression_to_latex(expression: str, wrap: bool = True):
def collect_docs_with_examples(root: YAMLRootModel) -> list[tuple[DocEntry, list[ExampleEntry]]]:
docs_with_examples = []
- current_doc: Optional[DocEntry] = None
+ current_doc: DocEntry | None = None
current_examples: list[ExampleEntry] = []
for entry in root.root:
if isinstance(entry, DocEntry):
@@ -391,7 +385,7 @@ def check() -> list[str]:
return errors
-def _validate_api_test_ref(label: str, ref: str, api_test_dir: str) -> Optional[str]:
+def _validate_api_test_ref(label: str, ref: str, api_test_dir: str) -> str | None:
parts = ref.split("::")
filename = parts[0]
filepath = os.path.join(api_test_dir, filename)
@@ -422,7 +416,7 @@ def _validate_api_test_ref(label: str, ref: str, api_test_dir: str) -> Optional[
return None
-def _validate_framework_test_ref(label: str, ref: str, workflow_dir: str) -> Optional[str]:
+def _validate_framework_test_ref(label: str, ref: str, workflow_dir: str) -> str | None:
"""Validate a framework test ref like 'collection_semantics_cat_0'."""
parts = ref.rsplit("_", 1)
if len(parts) != 2 or not parts[1].isdigit():
@@ -518,7 +512,6 @@ def generate_docs():
markdown_content.write(f"({example_entry.example.label})=\n")
markdown_content.write("Examples ")
for example_entry in examples:
-
example = example_entry.example
markdown_content.write("\n\n")
markdown_content.write(f":::{{admonition}} Example: `{example.label}` \n")
diff --git a/lib/galaxy/model/dataset_collections/workbook_util.py b/lib/galaxy/model/dataset_collections/workbook_util.py
index e687dfa3183..cf69f945161 100644
--- a/lib/galaxy/model/dataset_collections/workbook_util.py
+++ b/lib/galaxy/model/dataset_collections/workbook_util.py
@@ -20,9 +20,7 @@ from textwrap import wrap
from typing import (
Any,
Literal,
- Optional,
Protocol,
- Union,
)
from openpyxl import (
@@ -131,11 +129,11 @@ class ExcelReadOnlyWorkbook(ReadOnlyWorkbook):
class CsvDialect(BaseModel):
delimiter: str
- quote_character: Optional[str]
+ quote_character: str | None
double_quote: bool
skip_initial_space: bool
line_terminator: str
- escape_character: Optional[str]
+ escape_character: str | None
@staticmethod
def from_csv_dialect(dialect: type[Dialect]) -> "CsvDialect":
@@ -199,9 +197,9 @@ class CsvReaderReadOnlyWorkbook(ReadOnlyWorkbook):
def parse_format_messages(
workbook: ReadOnlyWorkbook,
-) -> list[Union[ContentTypeMessage, CsvDialectInferenceMessage]]:
+) -> list[ContentTypeMessage | CsvDialectInferenceMessage]:
"""Parse and return client-facing messages about parsing the target workbook."""
- messages: list[Union[ContentTypeMessage, CsvDialectInferenceMessage]] = []
+ messages: list[ContentTypeMessage | CsvDialectInferenceMessage] = []
if isinstance(workbook, ExcelReadOnlyWorkbook):
excel_content_type = workbook.content_type
diff --git a/lib/galaxy/model/deferred.py b/lib/galaxy/model/deferred.py
index e7c9870051b..bbf8e6be7de 100644
--- a/lib/galaxy/model/deferred.py
+++ b/lib/galaxy/model/deferred.py
@@ -4,8 +4,6 @@ import os
import shutil
from typing import (
NamedTuple,
- Optional,
- Union,
)
from sqlalchemy.orm import Session
@@ -78,10 +76,10 @@ class DatasetInstanceMaterializer:
def __init__(
self,
attached: bool,
- object_store_populator: Optional[ObjectStorePopulator] = None,
- transient_path_mapper: Optional[TransientPathMapper] = None,
- file_sources: Optional[ConfiguredFileSources] = None,
- sa_session: Optional[Session] = None,
+ object_store_populator: ObjectStorePopulator | None = None,
+ transient_path_mapper: TransientPathMapper | None = None,
+ file_sources: ConfiguredFileSources | None = None,
+ sa_session: Session | None = None,
user_context: OptionalUserContext = None,
):
"""Constructor for DatasetInstanceMaterializer.
@@ -104,8 +102,8 @@ class DatasetInstanceMaterializer:
def ensure_materialized(
self,
- dataset_instance: Union[HistoryDatasetAssociation, LibraryDatasetDatasetAssociation],
- target_history: Optional[History] = None,
+ dataset_instance: HistoryDatasetAssociation | LibraryDatasetDatasetAssociation,
+ target_history: History | None = None,
in_place: bool = False,
) -> HistoryDatasetAssociation:
"""Create a new detached dataset instance from the supplied instance.
@@ -153,9 +151,9 @@ class DatasetInstanceMaterializer:
materialized_dataset.hashes = materialized_dataset_hashes
target_source = self._find_closest_dataset_source(dataset)
transient_paths = None
- replacement_dataset: Optional[HistoryDatasetAssociation] = None
+ replacement_dataset: HistoryDatasetAssociation | None = None
- exception_materializing: Optional[Exception] = None
+ exception_materializing: Exception | None = None
history = target_history
if history is None and isinstance(dataset_instance, HistoryDatasetAssociation):
try:
@@ -176,7 +174,7 @@ class DatasetInstanceMaterializer:
sa_session.add(materialized_dataset)
sa_session.commit()
object_store_populator.set_dataset_object_store_id(materialized_dataset)
- user: Optional[User] = None
+ user: User | None = None
if history:
user = history.user
replacement_dataset = get_replacement_dataset(
@@ -327,7 +325,7 @@ class DatasetInstanceMaterializer:
return best_source
-CollectionInputT = Union[HistoryDatasetCollectionAssociation, DatasetCollectionElement]
+CollectionInputT = HistoryDatasetCollectionAssociation | DatasetCollectionElement
def materialize_collection_input(
@@ -370,7 +368,7 @@ def _materialize_collection(
def _materialize_collection_element(
element: DatasetCollectionElement, materializer: DatasetInstanceMaterializer
) -> DatasetCollectionElement:
- materialized_object: Union[DatasetCollection, HistoryDatasetAssociation, LibraryDatasetDatasetAssociation]
+ materialized_object: DatasetCollection | HistoryDatasetAssociation | LibraryDatasetDatasetAssociation
if element.is_collection:
assert element.child_collection
materialized_object = _materialize_collection(element.child_collection, materializer)
@@ -389,12 +387,12 @@ def _materialize_collection_element(
def materializer_factory(
attached: bool,
- object_store: Optional[ObjectStore] = None,
- object_store_populator: Optional[ObjectStorePopulator] = None,
- transient_path_mapper: Optional[TransientPathMapper] = None,
- transient_directory: Optional[str] = None,
- file_sources: Optional[ConfiguredFileSources] = None,
- sa_session: Optional[Session] = None,
+ object_store: ObjectStore | None = None,
+ object_store_populator: ObjectStorePopulator | None = None,
+ transient_path_mapper: TransientPathMapper | None = None,
+ transient_directory: str | None = None,
+ file_sources: ConfiguredFileSources | None = None,
+ sa_session: Session | None = None,
user_context: OptionalUserContext = None,
) -> DatasetInstanceMaterializer:
if object_store_populator is None and object_store is not None:
diff --git a/lib/galaxy/model/dereference.py b/lib/galaxy/model/dereference.py
index 6886e818704..e2c6a1f7b94 100644
--- a/lib/galaxy/model/dereference.py
+++ b/lib/galaxy/model/dereference.py
@@ -1,10 +1,6 @@
import logging
import os.path
from collections.abc import Sequence
-from typing import (
- Optional,
- Union,
-)
from sqlalchemy import (
false,
@@ -51,7 +47,7 @@ def dereference_to_model(
sa_session: galaxy_scoped_session,
user: User,
history: History,
- data_request_uri: Union[DataRequestUri, FileRequestUri, CollectionElementDataRequestUri],
+ data_request_uri: DataRequestUri | FileRequestUri | CollectionElementDataRequestUri,
add_to_history=True,
visible=True,
) -> HistoryDatasetAssociation:
@@ -103,7 +99,7 @@ def derefence_collection_element(
element: CollectionElementCollectionRequestUri,
parent_dataset_collection: DatasetCollection,
element_index: int,
- rows: Optional[dict[str, SampleSheetRow]] = None,
+ rows: dict[str, SampleSheetRow] | None = None,
):
child_dataset_collection = DatasetCollection(collection_type=element.collection_type)
@@ -140,7 +136,7 @@ def dereference_collection_dataset_element(
element: CollectionElementDataRequestUri,
parent_dataset_collection: DatasetCollection,
element_index: int,
- rows: Optional[dict[str, SampleSheetRow]] = None,
+ rows: dict[str, SampleSheetRow] | None = None,
):
hda = dereference_to_model(sa_session, user, history, element, add_to_history=False, visible=False)
history.stage_addition(hda)
@@ -235,13 +231,13 @@ def derefence_collection_to_model(
def get_replacement_dataset(
session: Session,
- user: Optional[User],
+ user: User | None,
dataset_sources: list[DatasetSource],
- dataset_hashes: Sequence[Union[DatasetHash, DatasetSourceHash]],
+ dataset_hashes: Sequence[DatasetHash | DatasetSourceHash],
extension: str,
object_store_id: str | None,
- created_from_basename: Optional[str] = None,
-) -> Optional[HistoryDatasetAssociation]:
+ created_from_basename: str | None = None,
+) -> HistoryDatasetAssociation | None:
"""
Get a replacement dataset for the given source URI and dataset hash.
If we already have such a dataset we don't need to create a new one.
diff --git a/lib/galaxy/model/index_filter_util.py b/lib/galaxy/model/index_filter_util.py
index 1cb75a26b81..756f94da219 100644
--- a/lib/galaxy/model/index_filter_util.py
+++ b/lib/galaxy/model/index_filter_util.py
@@ -1,9 +1,5 @@
"""Utility functions used to adapt galaxy.util.search to Galaxy model index queries."""
-from typing import (
- Union,
-)
-
from sqlalchemy import (
and_,
or_,
@@ -30,7 +26,7 @@ def text_column_filter(column, term: FilteredTerm):
return filter
-RawTextSearchableT = Union[BinaryExpression, InstrumentedAttribute]
+RawTextSearchableT = BinaryExpression | InstrumentedAttribute
def raw_text_column_filter(columns: list[RawTextSearchableT], term: RawTextTerm):
diff --git a/lib/galaxy/model/keyset_token_pagination.py b/lib/galaxy/model/keyset_token_pagination.py
index 0a7fca38838..3de88359986 100644
--- a/lib/galaxy/model/keyset_token_pagination.py
+++ b/lib/galaxy/model/keyset_token_pagination.py
@@ -5,7 +5,6 @@ import json
from dataclasses import dataclass
from typing import (
cast,
- Optional,
Protocol,
TypeVar,
)
@@ -90,9 +89,9 @@ class KeysetPagination:
def decode_token(
self,
- encoded: Optional[str],
+ encoded: str | None,
token_class: type[T],
- ) -> Optional[T]:
+ ) -> T | None:
"""Decode token using provided token class.
Args:
diff --git a/lib/galaxy/model/mapping.py b/lib/galaxy/model/mapping.py
index 5c92492f2c7..50d66d4c5ce 100644
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -28,7 +28,7 @@ metadata = mapper_registry.metadata
class GalaxyModelMapping(SharedModelMapping):
User: type["GalaxyUser"]
security_agent: GalaxyRBACAgent
- thread_local_log: Optional[local]
+ thread_local_log: local | None
def init(
@@ -41,7 +41,7 @@ def init(
trace_logger=None,
use_pbkdf2=True,
slow_query_log_threshold=0,
- thread_local_log: Optional[local] = None,
+ thread_local_log: local | None = None,
log_query_counts=False,
) -> GalaxyModelMapping:
# Build engine
diff --git a/lib/galaxy/model/metadata.py b/lib/galaxy/model/metadata.py
index 12cc8db83bf..0700372aea0 100644
--- a/lib/galaxy/model/metadata.py
+++ b/lib/galaxy/model/metadata.py
@@ -17,7 +17,6 @@ from collections.abc import (
from os.path import abspath
from typing import (
Any,
- Optional,
TYPE_CHECKING,
Union,
)
@@ -87,7 +86,7 @@ class MetadataCollection(Mapping):
def __init__(
self,
parent: Union["DatasetInstance", "NoneDataset"],
- session: Optional[Union["scoped_session", "SessionlessContext"]] = None,
+ session: Union["scoped_session", "SessionlessContext"] | None = None,
) -> None:
self.parent = parent
self._session = session
diff --git a/lib/galaxy/model/migrations/__init__.py b/lib/galaxy/model/migrations/__init__.py
index e5b4d92294d..ce95e2accca 100644
--- a/lib/galaxy/model/migrations/__init__.py
+++ b/lib/galaxy/model/migrations/__init__.py
@@ -6,7 +6,6 @@ from typing import (
NamedTuple,
NewType,
NoReturn,
- Optional,
)
import alembic
@@ -103,13 +102,13 @@ class AlembicManager(BaseAlembicManager):
log.info(f"Revision {db_head} does not exist in the script directory.")
return False
- def get_model_db_head(self, model: ModelId) -> Optional[str]:
+ def get_model_db_head(self, model: ModelId) -> str | None:
return self._get_head_revision(model, cast(Iterable[str], self.db_heads))
- def get_model_script_head(self, model: ModelId) -> Optional[str]:
+ def get_model_script_head(self, model: ModelId) -> str | None:
return self._get_head_revision(model, self.script_directory.get_heads())
- def _get_head_revision(self, model: ModelId, heads: Iterable[str]) -> Optional[str]:
+ def _get_head_revision(self, model: ModelId, heads: Iterable[str]) -> str | None:
for head in heads:
revision = self._get_revision(head)
if revision and model in revision.branch_labels:
@@ -145,11 +144,11 @@ def verify_databases_via_script(
def verify_databases(
gxy_engine: Engine,
- gxy_template: Optional[str],
- gxy_encoding: Optional[str],
- tsi_engine: Optional[Engine],
- tsi_template: Optional[str],
- tsi_encoding: Optional[str],
+ gxy_template: str | None,
+ gxy_encoding: str | None,
+ tsi_engine: Engine | None,
+ tsi_template: str | None,
+ tsi_encoding: str | None,
is_auto_migrate: bool,
) -> None:
# Verify gxy model.
@@ -172,10 +171,10 @@ class DatabaseStateVerifier:
self,
engine: Engine,
model: ModelId,
- database_template: Optional[str],
- database_encoding: Optional[str],
+ database_template: str | None,
+ database_encoding: str | None,
is_auto_migrate: bool,
- is_new_database: Optional[bool] = False,
+ is_new_database: bool | None = False,
) -> None:
self.engine = engine
self.model = model
@@ -186,8 +185,8 @@ class DatabaseStateVerifier:
# True if database has been initialized for another model.
self.is_new_database = is_new_database
# These values may or may not be required, so do a lazy load.
- self._db_state: Optional[DatabaseStateCache] = None
- self._alembic_manager: Optional[AlembicManager] = None
+ self._db_state: DatabaseStateCache | None = None
+ self._alembic_manager: AlembicManager | None = None
@property
def is_auto_migrate(self) -> bool:
diff --git a/lib/galaxy/model/migrations/alembic/versions_gxy/28885b317f78_add_tool_request_request_state.py b/lib/galaxy/model/migrations/alembic/versions_gxy/28885b317f78_add_tool_request_request_state.py
index 1fa243f1f99..3b0b3dc5782 100644
--- a/lib/galaxy/model/migrations/alembic/versions_gxy/28885b317f78_add_tool_request_request_state.py
+++ b/lib/galaxy/model/migrations/alembic/versions_gxy/28885b317f78_add_tool_request_request_state.py
@@ -127,9 +127,8 @@ def _backfill_identity_hash() -> None:
def _identity_hash_for_row(row) -> str:
- dynamic_tool_id = row["dynamic_tool_id"]
identity: tuple[str, ...]
- if dynamic_tool_id is not None:
+ if (dynamic_tool_id := row["dynamic_tool_id"]) is not None:
identity = ("dynamic", str(dynamic_tool_id))
else:
identity = ("static", row["tool_id"] or "", row["tool_version"] or "")
diff --git a/lib/galaxy/model/migrations/base.py b/lib/galaxy/model/migrations/base.py
index d48388875af..f9c79eaa3c1 100644
--- a/lib/galaxy/model/migrations/base.py
+++ b/lib/galaxy/model/migrations/base.py
@@ -14,8 +14,6 @@ from argparse import (
from collections.abc import Iterable
from typing import (
cast,
- Optional,
- Union,
)
import alembic
@@ -178,12 +176,12 @@ class BaseDbScript(abc.ABC):
"""Facade for common database schema migration operations."""
@abc.abstractmethod
- def _set_dburl(self, config_file: Optional[str] = None) -> None: ...
+ def _set_dburl(self, config_file: str | None = None) -> None: ...
@abc.abstractmethod
def _upgrade_to_head(self, is_sql_mode: bool): ...
- def __init__(self, config_file: Optional[str] = None) -> None:
+ def __init__(self, config_file: str | None = None) -> None:
self.alembic_config = self._get_alembic_cfg()
self._set_dburl(config_file)
@@ -303,7 +301,7 @@ class BaseAlembicManager(abc.ABC):
def _get_alembic_root(self): ...
@staticmethod
- def is_at_revision(engine: Engine, revision: Union[str, Iterable[str]]) -> bool:
+ def is_at_revision(engine: Engine, revision: str | Iterable[str]) -> bool:
"""
True if revision is a subset of the set of version heads stored in the database.
"""
@@ -313,15 +311,15 @@ class BaseAlembicManager(abc.ABC):
db_version_heads = context.get_current_heads()
return set(revision) <= set(db_version_heads)
- def __init__(self, engine: Engine, config_dict: Optional[dict] = None) -> None:
+ def __init__(self, engine: Engine, config_dict: dict | None = None) -> None:
self.engine = engine
self.alembic_cfg = self._load_config(config_dict)
self.script_directory = ScriptDirectory.from_config(self.alembic_cfg)
- self._db_heads: Optional[Iterable[str]]
+ self._db_heads: Iterable[str] | None
self._reset_db_heads()
@property
- def db_heads(self) -> Optional[Iterable]:
+ def db_heads(self) -> Iterable | None:
if self._db_heads is None: # Explicitly check for None: could be an empty tuple.
with self.engine.connect() as conn:
context: MigrationContext = MigrationContext.configure(conn)
@@ -331,12 +329,12 @@ class BaseAlembicManager(abc.ABC):
self._db_heads = listify(self._db_heads)
return self._db_heads
- def stamp_revision(self, revision: Union[str, Iterable[str]]) -> None:
+ def stamp_revision(self, revision: str | Iterable[str]) -> None:
"""Partial proxy to alembic's stamp command."""
command.stamp(self.alembic_cfg, revision) # type: ignore[arg-type] # https://alembic.sqlalchemy.org/en/latest/api/commands.html#alembic.command.stamp.params.revision
self._reset_db_heads()
- def _load_config(self, config_dict: Optional[dict]) -> Config:
+ def _load_config(self, config_dict: dict | None) -> Config:
alembic_root = self._get_alembic_root()
_alembic_file = os.path.join(alembic_root, "alembic.ini")
config = Config(_alembic_file)
@@ -347,7 +345,7 @@ class BaseAlembicManager(abc.ABC):
config.set_main_option(key, value)
return config
- def _get_revision(self, revision_id: str) -> Optional[Script]:
+ def _get_revision(self, revision_id: str) -> Script | None:
try:
return self.script_directory.get_revision(revision_id)
except alembic.util.exc.CommandError as e:
@@ -395,14 +393,14 @@ class DatabaseStateCache:
metadata.reflect(bind=conn)
return metadata
- def _load_sqlalchemymigrate_version(self, conn: Connection) -> Optional[int]:
+ def _load_sqlalchemymigrate_version(self, conn: Connection) -> int | None:
if self.has_sqlalchemymigrate_version_table():
sql = text(f"select version from {SQLALCHEMYMIGRATE_TABLE}")
return conn.execute(sql).scalar()
return None
-def pop_arg_from_args(args: list[str], arg_name) -> Optional[str]:
+def pop_arg_from_args(args: list[str], arg_name) -> str | None:
"""
Pop and return argument name and value from args if arg_name is in args.
"""
@@ -431,7 +429,7 @@ def load_metadata(metadata: MetaData, engine: Engine) -> None:
metadata.create_all(bind=conn)
-def listify(data: Union[str, Iterable[str]]) -> Iterable[str]:
+def listify(data: str | Iterable[str]) -> Iterable[str]:
if not isinstance(data, (list, tuple)):
return [cast(str, data)]
return data
diff --git a/lib/galaxy/model/migrations/data_fixes/association_table_fixer.py b/lib/galaxy/model/migrations/data_fixes/association_table_fixer.py
index 805b6069a36..d5525d2f769 100644
--- a/lib/galaxy/model/migrations/data_fixes/association_table_fixer.py
+++ b/lib/galaxy/model/migrations/data_fixes/association_table_fixer.py
@@ -19,7 +19,6 @@ from galaxy.model import (
class AssociationNullFix(ABC):
-
def __init__(self, connection):
self.connection = connection
self.assoc_model = self.association_model()
@@ -57,7 +56,6 @@ class AssociationNullFix(ABC):
class UserGroupAssociationNullFix(AssociationNullFix):
-
def association_model(self):
return UserGroupAssociation
@@ -66,7 +64,6 @@ class UserGroupAssociationNullFix(AssociationNullFix):
class UserRoleAssociationNullFix(AssociationNullFix):
-
def association_model(self):
return UserRoleAssociation
@@ -75,7 +72,6 @@ class UserRoleAssociationNullFix(AssociationNullFix):
class GroupRoleAssociationNullFix(AssociationNullFix):
-
def association_model(self):
return GroupRoleAssociation
@@ -84,7 +80,6 @@ class GroupRoleAssociationNullFix(AssociationNullFix):
class AssociationDuplicateFix(ABC):
-
def __init__(self, connection):
self.connection = connection
self.assoc_model = self.association_model()
@@ -134,7 +129,6 @@ class AssociationDuplicateFix(ABC):
class UserGroupAssociationDuplicateFix(AssociationDuplicateFix):
-
def association_model(self):
return UserGroupAssociation
@@ -156,7 +150,6 @@ class UserGroupAssociationDuplicateFix(AssociationDuplicateFix):
class UserRoleAssociationDuplicateFix(AssociationDuplicateFix):
-
def association_model(self):
return UserRoleAssociation
@@ -178,7 +171,6 @@ class UserRoleAssociationDuplicateFix(AssociationDuplicateFix):
class GroupRoleAssociationDuplicateFix(AssociationDuplicateFix):
-
def association_model(self):
return GroupRoleAssociation
diff --git a/lib/galaxy/model/migrations/data_fixes/custos_to_psa.py b/lib/galaxy/model/migrations/data_fixes/custos_to_psa.py
index 321975674a3..5ae0b3885a7 100644
--- a/lib/galaxy/model/migrations/data_fixes/custos_to_psa.py
+++ b/lib/galaxy/model/migrations/data_fixes/custos_to_psa.py
@@ -3,7 +3,6 @@
from datetime import datetime
from typing import (
cast,
- Optional,
)
import jwt
@@ -26,7 +25,7 @@ PSA_TABLE = "oidc_user_authnz_tokens"
CUSTOS_ASSOC_TYPE = "custos_migrated"
-def _extract_iat_from_token(token: Optional[str]) -> Optional[int]:
+def _extract_iat_from_token(token: str | None) -> int | None:
"""
Extract the 'iat' (issued at) claim from a JWT token.
Returns None if the token cannot be decoded or doesn't have an iat claim.
@@ -70,8 +69,8 @@ def get_psa_table(connection: Connection) -> Table:
def migrate_custos_tokens_to_psa(
connection: Connection,
- custos_table: Optional[Table] = None,
- psa_table: Optional[Table] = None,
+ custos_table: Table | None = None,
+ psa_table: Table | None = None,
) -> int:
"""
Transform Custos tokens into PSA tokens and insert them into oidc_user_authnz_tokens.
@@ -151,8 +150,8 @@ def migrate_custos_tokens_to_psa(
def remove_migrated_psa_tokens(
connection: Connection,
- custos_table: Optional[Table] = None,
- psa_table: Optional[Table] = None,
+ custos_table: Table | None = None,
+ psa_table: Table | None = None,
) -> int:
"""
Remove PSA tokens that were created during the Custos migration.
@@ -183,8 +182,8 @@ def remove_migrated_psa_tokens(
def restore_custos_tokens_from_psa(
connection: Connection,
- custos_table: Optional[Table] = None,
- psa_table: Optional[Table] = None,
+ custos_table: Table | None = None,
+ psa_table: Table | None = None,
) -> int:
"""
Restore Custos tokens from PSA rows that originated from the migration.
diff --git a/lib/galaxy/model/migrations/data_fixes/user_table_fixer.py b/lib/galaxy/model/migrations/data_fixes/user_table_fixer.py
index 61feb7646f1..ba8a27a7862 100644
--- a/lib/galaxy/model/migrations/data_fixes/user_table_fixer.py
+++ b/lib/galaxy/model/migrations/data_fixes/user_table_fixer.py
@@ -12,7 +12,6 @@ from galaxy.model import User
class UsernameDeduplicator:
-
def __init__(self, connection):
self.connection = connection
@@ -51,7 +50,6 @@ class UsernameDeduplicator:
class EmailDeduplicator:
-
def __init__(self, connection):
self.connection = connection
diff --git a/lib/galaxy/model/migrations/dbscript.py b/lib/galaxy/model/migrations/dbscript.py
index 381bc68b4b6..f4a4c054bab 100644
--- a/lib/galaxy/model/migrations/dbscript.py
+++ b/lib/galaxy/model/migrations/dbscript.py
@@ -2,7 +2,6 @@ import logging
import os
import sys
from argparse import Namespace
-from typing import Optional
from galaxy.model.migrations import verify_databases_via_script
from galaxy.model.migrations.base import (
@@ -56,7 +55,7 @@ class DbScript(BaseDbScript):
def _revision_tags(self):
return {f"release_{k}": v for k, v in REVISION_TAGS.items()} | REVISION_TAGS
- def _set_dburl(self, config_file: Optional[str] = None) -> None:
+ def _set_dburl(self, config_file: str | None = None) -> None:
gxy_config, tsi_config, _ = get_configuration_from_file(os.getcwd(), config_file)
self.gxy_url = gxy_config.url
self.tsi_url = tsi_config.url
diff --git a/lib/galaxy/model/migrations/scripts.py b/lib/galaxy/model/migrations/scripts.py
index 16ac4b1242e..4ce5d57aa65 100644
--- a/lib/galaxy/model/migrations/scripts.py
+++ b/lib/galaxy/model/migrations/scripts.py
@@ -1,8 +1,5 @@
import os
import sys
-from typing import (
- Optional,
-)
import alembic.config
from alembic.config import Config
@@ -75,7 +72,7 @@ def get_configuration(argv: list[str], cwd: str) -> tuple[DatabaseConfig, Databa
def get_configuration_from_file(
- cwd: str, config_file: Optional[str] = None
+ cwd: str, config_file: str | None = None
) -> tuple[DatabaseConfig, DatabaseConfig, bool]:
if config_file is None:
cwds = [cwd, os.path.join(cwd, CONFIG_DIR_NAME)]
diff --git a/lib/galaxy/model/migrations/util.py b/lib/galaxy/model/migrations/util.py
index cfa3091152b..56fe7870c71 100644
--- a/lib/galaxy/model/migrations/util.py
+++ b/lib/galaxy/model/migrations/util.py
@@ -7,7 +7,6 @@ from collections.abc import Sequence
from contextlib import contextmanager
from typing import (
Any,
- Optional,
)
import sqlalchemy as sa
@@ -23,7 +22,7 @@ log = logging.getLogger(__name__)
class DDLOperation(ABC):
"""Base class for all DDL operations."""
- def run(self) -> Optional[Any]:
+ def run(self) -> Any | None:
if not self._is_repair_mode():
return self.execute()
else:
@@ -34,7 +33,7 @@ class DDLOperation(ABC):
return None
@abstractmethod
- def execute(self) -> Optional[Any]: ...
+ def execute(self) -> Any | None: ...
@abstractmethod
def pre_execute_check(self) -> bool: ...
@@ -64,13 +63,13 @@ class DDLAlterOperation(DDLOperation):
def __init__(self, table_name: str) -> None:
self.table_name = table_name
- def run(self) -> Optional[Any]:
+ def run(self) -> Any | None:
if context.is_offline_mode():
log.info("Generation of `alter` statements is disabled in offline mode.")
return None
return super().run()
- def execute(self) -> Optional[Any]:
+ def execute(self) -> Any | None:
if _is_sqlite():
with legacy_alter_table(), op.batch_alter_table(self.table_name) as batch_op:
return self.batch_execute(batch_op)
@@ -78,10 +77,10 @@ class DDLAlterOperation(DDLOperation):
return self.non_batch_execute() # use regular op context for non-sqlite db
@abstractmethod
- def batch_execute(self, batch_op) -> Optional[Any]: ...
+ def batch_execute(self, batch_op) -> Any | None: ...
@abstractmethod
- def non_batch_execute(self) -> Optional[Any]: ...
+ def non_batch_execute(self) -> Any | None: ...
class CreateTable(DDLOperation):
@@ -91,7 +90,7 @@ class CreateTable(DDLOperation):
self.table_name = table_name
self.columns = columns
- def execute(self) -> Optional[sa.Table]:
+ def execute(self) -> sa.Table | None:
return op.create_table(self.table_name, *self.columns)
def pre_execute_check(self) -> bool:
@@ -297,7 +296,7 @@ class DropConstraint(DDLAlterOperation):
self._log_object_does_not_exist_message(name)
-def create_table(table_name: str, *columns: sa.schema.SchemaItem) -> Optional[sa.Table]:
+def create_table(table_name: str, *columns: sa.schema.SchemaItem) -> sa.Table | None:
return CreateTable(table_name, *columns).run()
diff --git a/lib/galaxy/model/orm/engine_factory.py b/lib/galaxy/model/orm/engine_factory.py
index aaf304457ec..f24beb30bda 100644
--- a/lib/galaxy/model/orm/engine_factory.py
+++ b/lib/galaxy/model/orm/engine_factory.py
@@ -7,7 +7,6 @@ import time
from multiprocessing.util import register_after_fork
from typing import (
Any,
- Union,
)
from sqlalchemy import (
@@ -52,7 +51,7 @@ def pretty_stack():
def build_engine(
url: str,
- engine_options: Union[dict[str, Any], None] = None,
+ engine_options: dict[str, Any] | None = None,
database_query_profiling_proxy=False,
trace_logger=None,
slow_query_log_threshold=0,
diff --git a/lib/galaxy/model/security.py b/lib/galaxy/model/security.py
index 2ced36841bd..38b17a5e69e 100644
--- a/lib/galaxy/model/security.py
+++ b/lib/galaxy/model/security.py
@@ -2,9 +2,6 @@ import logging
import socket
import sqlite3
from datetime import timedelta
-from typing import (
- Optional,
-)
from sqlalchemy import (
and_,
@@ -1412,8 +1409,8 @@ WHERE history.user_id != :user_id and history_dataset_association.dataset_id = :
self,
user: User,
*,
- group_ids: Optional[list[int]] = None,
- role_ids: Optional[list[int]] = None,
+ group_ids: list[int] | None = None,
+ role_ids: list[int] | None = None,
) -> None:
"""
Set user groups and user roles, replacing current associations.
@@ -1434,8 +1431,8 @@ WHERE history.user_id != :user_id and history_dataset_association.dataset_id = :
self,
group: Group,
*,
- user_ids: Optional[list[int]] = None,
- role_ids: Optional[list[int]] = None,
+ user_ids: list[int] | None = None,
+ role_ids: list[int] | None = None,
) -> None:
"""
Set group users and group roles, replacing current associations.
@@ -1456,8 +1453,8 @@ WHERE history.user_id != :user_id and history_dataset_association.dataset_id = :
self,
role: Role,
*,
- user_ids: Optional[list[int]] = None,
- group_ids: Optional[list[int]] = None,
+ user_ids: list[int] | None = None,
+ group_ids: list[int] | None = None,
) -> None:
"""
Set role users and role groups, replacing current associations.
diff --git a/lib/galaxy/model/store/__init__.py b/lib/galaxy/model/store/__init__.py
index 396c03d82ab..a2cb45d7b50 100644
--- a/lib/galaxy/model/store/__init__.py
+++ b/lib/galaxy/model/store/__init__.py
@@ -134,7 +134,7 @@ if TYPE_CHECKING:
log = logging.getLogger(__name__)
-ObjectKeyType = Union[str, int]
+ObjectKeyType = str | int
ATTRS_FILENAME_HISTORY = "history_attrs.txt"
ATTRS_FILENAME_DATASETS = "datasets_attrs.txt"
@@ -184,14 +184,14 @@ class ImportDiscardedDataType(Enum):
class DatasetAttributeImportModel(BaseModel):
- state: Optional[DatasetStateField] = None
- external_filename: Optional[str] = None
- _extra_files_path: Optional[str] = None
- file_size: Optional[int] = None
- object_store_id: Optional[str] = None
- total_size: Optional[int] = None
- created_from_basename: Optional[str] = None
- uuid: Optional[str] = None
+ state: DatasetStateField | None = None
+ external_filename: str | None = None
+ _extra_files_path: str | None = None
+ file_size: int | None = None
+ object_store_id: str | None = None
+ total_size: int | None = None
+ created_from_basename: str | None = None
+ uuid: str | None = None
model_config = ConfigDict(extra="ignore")
@@ -208,7 +208,7 @@ class ImportOptions:
self,
allow_edit: bool = False,
allow_library_creation: bool = False,
- allow_dataset_object_edit: Optional[bool] = None,
+ allow_dataset_object_edit: bool | None = None,
discarded_data: ImportDiscardedDataType = DEFAULT_DISCARDED_DATA_TYPE,
) -> None:
self.allow_edit = allow_edit
@@ -259,7 +259,7 @@ class SessionlessContext:
def replace_metadata_file(
metadata: dict[str, Any],
dataset_instance: model.DatasetInstance,
- sa_session: Union[SessionlessContext, scoped_session],
+ sa_session: SessionlessContext | scoped_session,
) -> dict[str, Any]:
def remap_objects(p, k, obj):
if isinstance(obj, dict) and "model_class" in obj and obj["model_class"] == "MetadataFile":
@@ -272,16 +272,16 @@ def replace_metadata_file(
class ModelImportStore(metaclass=abc.ABCMeta):
- app: Optional[StoreAppProtocol]
+ app: StoreAppProtocol | None
archive_dir: str
- sa_session: Union[scoped_session, SessionlessContext]
+ sa_session: scoped_session | SessionlessContext
def __init__(
self,
- import_options: Optional[ImportOptions] = None,
- app: Optional[StoreAppProtocol] = None,
- user: Optional[model.User] = None,
- object_store: Optional[ObjectStore] = None,
+ import_options: ImportOptions | None = None,
+ app: StoreAppProtocol | None = None,
+ user: model.User | None = None,
+ object_store: ObjectStore | None = None,
tag_handler: Optional["GalaxyTagHandlerSession"] = None,
) -> None:
if object_store is None:
@@ -351,7 +351,7 @@ class ModelImportStore(metaclass=abc.ABCMeta):
"""
@property
- def file_source_root(self) -> Optional[str]:
+ def file_source_root(self) -> str | None:
"""Source of valid file data."""
return None
@@ -364,8 +364,8 @@ class ModelImportStore(metaclass=abc.ABCMeta):
@contextlib.contextmanager
def target_history(
- self, default_history: Optional[model.History] = None, legacy_history_naming: bool = True
- ) -> Iterator[Optional[model.History]]:
+ self, default_history: model.History | None = None, legacy_history_naming: bool = True
+ ) -> Iterator[model.History | None]:
new_history = None
if self.defines_new_history():
@@ -397,7 +397,7 @@ class ModelImportStore(metaclass=abc.ABCMeta):
if self.user:
add_item_annotation(self.sa_session, self.user, new_history, history_properties.get("annotation"))
- history: Optional[model.History] = new_history
+ history: model.History | None = new_history
else:
history = default_history
@@ -409,7 +409,7 @@ class ModelImportStore(metaclass=abc.ABCMeta):
self._flush()
def perform_import(
- self, history: Optional[model.History] = None, new_history: bool = False, job: Optional[model.Job] = None
+ self, history: model.History | None = None, new_history: bool = False, job: model.Job | None = None
) -> "ObjectImportTracker":
object_import_tracker = ObjectImportTracker()
@@ -481,9 +481,9 @@ class ModelImportStore(metaclass=abc.ABCMeta):
self,
object_import_tracker: "ObjectImportTracker",
datasets_attrs: list[dict[str, Any]],
- history: Optional[model.History],
+ history: model.History | None,
new_history: bool,
- job: Optional[model.Job],
+ job: model.Job | None,
) -> None:
object_key = self.object_key
@@ -844,7 +844,7 @@ class ModelImportStore(metaclass=abc.ABCMeta):
self,
object_import_tracker: "ObjectImportTracker",
collections_attrs: list[dict[str, Any]],
- history: Optional[model.History],
+ history: model.History | None,
new_history: bool,
) -> None:
object_key = self.object_key
@@ -1060,7 +1060,7 @@ class ModelImportStore(metaclass=abc.ABCMeta):
else:
hdca_copied_from_sinks[copied_from_object_key] = dataset_collection_key
- def _reassign_hids(self, object_import_tracker: "ObjectImportTracker", history: Optional[model.History]) -> None:
+ def _reassign_hids(self, object_import_tracker: "ObjectImportTracker", history: model.History | None) -> None:
# assign HIDs for newly created objects that didn't match original history
requires_hid = object_import_tracker.requires_hid
requires_hid_len = len(requires_hid)
@@ -1079,7 +1079,7 @@ class ModelImportStore(metaclass=abc.ABCMeta):
self._flush()
def _import_workflow_invocations(
- self, object_import_tracker: "ObjectImportTracker", history: Optional[model.History]
+ self, object_import_tracker: "ObjectImportTracker", history: model.History | None
) -> None:
#
# Create jobs.
@@ -1303,7 +1303,7 @@ class ModelImportStore(metaclass=abc.ABCMeta):
assoc.workflow_step = workflow_step
self._session_add(assoc)
- def _import_jobs(self, object_import_tracker: "ObjectImportTracker", history: Optional[model.History]) -> None:
+ def _import_jobs(self, object_import_tracker: "ObjectImportTracker", history: model.History | None) -> None:
self._flush()
object_key = self.object_key
@@ -1414,11 +1414,11 @@ class ModelImportStore(metaclass=abc.ABCMeta):
def _copied_from_object_key(
copied_from_chain: list[ObjectKeyType],
- objects_by_key: Union[
- dict[ObjectKeyType, model.HistoryDatasetAssociation],
- dict[ObjectKeyType, model.HistoryDatasetCollectionAssociation],
- ],
-) -> Optional[ObjectKeyType]:
+ objects_by_key: (
+ dict[ObjectKeyType, model.HistoryDatasetAssociation]
+ | dict[ObjectKeyType, model.HistoryDatasetCollectionAssociation]
+ ),
+) -> ObjectKeyType | None:
if len(copied_from_chain) == 0:
return None
@@ -1478,11 +1478,9 @@ class ObjectImportTracker:
self.requires_hid = []
self.copy_hid_for = []
- self.new_history: Optional[model.History] = None
+ self.new_history: model.History | None = None
- def find_hda(
- self, input_key: ObjectKeyType, hda_id: Optional[int] = None
- ) -> Optional[model.HistoryDatasetAssociation]:
+ def find_hda(self, input_key: ObjectKeyType, hda_id: int | None = None) -> model.HistoryDatasetAssociation | None:
hda = None
if input_key in self.hdas_by_key:
hda = self.hdas_by_key[input_key]
@@ -1493,7 +1491,7 @@ class ObjectImportTracker:
hda = self.hdas_by_key[self.hda_copied_from_sinks[input_key]]
return hda
- def find_hdca(self, input_key: ObjectKeyType) -> Optional[model.HistoryDatasetCollectionAssociation]:
+ def find_hdca(self, input_key: ObjectKeyType) -> model.HistoryDatasetCollectionAssociation | None:
hdca = None
if input_key in self.hdcas_by_key:
hdca = self.hdcas_by_key[input_key]
@@ -1503,7 +1501,7 @@ class ObjectImportTracker:
hdca = self.hdcas_by_key[self.hdca_copied_from_sinks[input_key]]
return hdca
- def find_dce(self, input_key: ObjectKeyType) -> Optional[model.DatasetCollectionElement]:
+ def find_dce(self, input_key: ObjectKeyType) -> model.DatasetCollectionElement | None:
dce = None
if input_key in self.dces_by_key:
dce = self.dces_by_key[input_key]
@@ -1720,7 +1718,7 @@ class BaseDirectoryImportModelStore(ModelImportStore):
def restore_times(
- model_object: Union[model.Job, model.WorkflowInvocation, model.WorkflowInvocationStep], attrs: dict[str, Any]
+ model_object: model.Job | model.WorkflowInvocation | model.WorkflowInvocationStep, attrs: dict[str, Any]
) -> None:
model_object.create_time = datetime.datetime.fromisoformat(attrs["create_time"])
model_object.update_time = datetime.datetime.fromisoformat(attrs["update_time"])
@@ -1931,9 +1929,7 @@ class ModelExportStore(metaclass=abc.ABCMeta):
"""Export workflow invocation to store."""
@abc.abstractmethod
- def add_dataset_collection(
- self, collection: Union[model.DatasetCollection, model.HistoryDatasetCollectionAssociation]
- ):
+ def add_dataset_collection(self, collection: model.DatasetCollection | model.HistoryDatasetCollectionAssociation):
"""Add Dataset Collection or HDCA to export store."""
@abc.abstractmethod
@@ -1954,21 +1950,21 @@ class ModelExportStore(metaclass=abc.ABCMeta):
class DirectoryModelExportStore(ModelExportStore):
- app: Optional[StoreAppProtocol]
- file_sources: Optional[ConfiguredFileSources]
+ app: StoreAppProtocol | None
+ file_sources: ConfiguredFileSources | None
def __init__(
self,
export_directory: StrPath,
- app: Optional[StoreAppProtocol] = None,
- file_sources: Optional[ConfiguredFileSources] = None,
+ app: StoreAppProtocol | None = None,
+ file_sources: ConfiguredFileSources | None = None,
for_edit: bool = False,
- serialize_dataset_objects: Optional[bool] = None,
- export_files: Optional[str] = None,
+ serialize_dataset_objects: bool | None = None,
+ export_files: str | None = None,
strip_metadata_files: bool = True,
serialize_jobs: bool = True,
user_context=None,
- ignore_errors: Optional[bool] = False,
+ ignore_errors: bool | None = False,
) -> None:
"""
:param export_directory: path to export directory. Will be created if it does not exist.
@@ -2011,14 +2007,14 @@ class DirectoryModelExportStore(ModelExportStore):
self.included_datasets: dict[model.DatasetInstance, tuple[model.DatasetInstance, bool]] = {}
self.dataset_implicit_conversions: dict[model.DatasetInstance, model.ImplicitlyConvertedDatasetAssociation] = {}
self.included_collections: dict[
- Union[model.DatasetCollection, model.HistoryDatasetCollectionAssociation],
- Union[model.DatasetCollection, model.HistoryDatasetCollectionAssociation],
+ model.DatasetCollection | model.HistoryDatasetCollectionAssociation,
+ model.DatasetCollection | model.HistoryDatasetCollectionAssociation,
] = {}
self.included_libraries: list[model.Library] = []
self.included_library_folders: list[model.LibraryFolder] = []
self.included_invocations: list[model.WorkflowInvocation] = []
self.collection_datasets: set[int] = set()
- self.dataset_id_to_path: dict[int, tuple[Optional[str], Optional[str]]] = {}
+ self.dataset_id_to_path: dict[int, tuple[str | None, str | None]] = {}
self.job_output_dataset_associations: dict[int, dict[str, model.DatasetInstance]] = {}
@@ -2112,7 +2108,7 @@ class DirectoryModelExportStore(ModelExportStore):
def exported_key(
self,
obj: model.RepresentById,
- ) -> Union[str, int]:
+ ) -> str | int:
return self.serialization_options.get_identifier(self.security, obj)
def __enter__(self) -> "DirectoryModelExportStore":
@@ -2133,7 +2129,7 @@ class DirectoryModelExportStore(ModelExportStore):
def export_jobs(
self,
jobs: Iterable[model.Job],
- jobs_attrs: Optional[list[dict[str, Any]]] = None,
+ jobs_attrs: list[dict[str, Any]] | None = None,
include_job_data: bool = True,
) -> list[dict[str, Any]]:
"""
@@ -2150,12 +2146,12 @@ class DirectoryModelExportStore(ModelExportStore):
if include_job_data:
# -- Get input, output datasets. --
- input_dataset_mapping: dict[str, list[Union[str, int]]] = {}
- output_dataset_mapping: dict[str, list[Union[str, int]]] = {}
- input_dataset_collection_mapping: dict[str, list[Union[str, int]]] = {}
- input_dataset_collection_element_mapping: dict[str, list[Union[str, int]]] = {}
- output_dataset_collection_mapping: dict[str, list[Union[str, int]]] = {}
- implicit_output_dataset_collection_mapping: dict[str, list[Union[str, int]]] = {}
+ input_dataset_mapping: dict[str, list[str | int]] = {}
+ output_dataset_mapping: dict[str, list[str | int]] = {}
+ input_dataset_collection_mapping: dict[str, list[str | int]] = {}
+ input_dataset_collection_element_mapping: dict[str, list[str | int]] = {}
+ output_dataset_collection_mapping: dict[str, list[str | int]] = {}
+ implicit_output_dataset_collection_mapping: dict[str, list[str | int]] = {}
for id_assoc in job.input_datasets:
# Optional data inputs will not have a dataset.
@@ -2391,7 +2387,7 @@ class DirectoryModelExportStore(ModelExportStore):
def export_collection(
self,
- collection: Union[model.DatasetCollection, model.HistoryDatasetCollectionAssociation],
+ collection: model.DatasetCollection | model.HistoryDatasetCollectionAssociation,
include_deleted: bool = False,
include_hidden: bool = False,
) -> None:
@@ -2412,7 +2408,7 @@ class DirectoryModelExportStore(ModelExportStore):
self.collection_datasets.add(collection_dataset.id)
def add_dataset_collection(
- self, collection: Union[model.DatasetCollection, model.HistoryDatasetCollectionAssociation]
+ self, collection: model.DatasetCollection | model.HistoryDatasetCollectionAssociation
) -> None:
self.included_collections[collection] = collection
@@ -2486,7 +2482,7 @@ class DirectoryModelExportStore(ModelExportStore):
jobs_attrs = []
for job_id, job_output_dataset_associations in self.job_output_dataset_associations.items():
- output_dataset_mapping: dict[str, list[Union[str, int]]] = {}
+ output_dataset_mapping: dict[str, list[str | int]] = {}
for name, dataset in job_output_dataset_associations.items():
if name not in output_dataset_mapping:
output_dataset_mapping[name] = []
@@ -2592,7 +2588,7 @@ class DirectoryModelExportStore(ModelExportStore):
dump({"galaxy_export_version": GALAXY_EXPORT_VERSION}, export_attrs_out)
def __exit__(
- self, exc_type: Optional[type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]
+ self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None
) -> bool:
if exc_type is None:
self._finalize()
@@ -2606,7 +2602,7 @@ class WriteCrates:
export_directory: StrPath
included_datasets: dict[model.DatasetInstance, tuple[model.DatasetInstance, bool]]
dataset_implicit_conversions: dict[model.DatasetInstance, model.ImplicitlyConvertedDatasetAssociation]
- dataset_id_to_path: dict[int, tuple[Optional[str], Optional[str]]]
+ dataset_id_to_path: dict[int, tuple[str | None, str | None]]
@property
@abc.abstractmethod
@@ -2737,10 +2733,10 @@ class BcoExportOptions:
galaxy_url: str
galaxy_version: str
merge_history_metadata: bool = False
- override_environment_variables: Optional[dict[str, str]] = None
- override_empirical_error: Optional[dict[str, str]] = None
- override_algorithmic_error: Optional[dict[str, str]] = None
- override_xref: Optional[list[XrefItem]] = None
+ override_environment_variables: dict[str, str] | None = None
+ override_empirical_error: dict[str, str] | None = None
+ override_algorithmic_error: dict[str, str] | None = None
+ override_xref: list[XrefItem] | None = None
class FileSourceModelExportStore(abc.ABC, DirectoryModelExportStore):
@@ -2748,7 +2744,7 @@ class FileSourceModelExportStore(abc.ABC, DirectoryModelExportStore):
Export to file sources, from where data can be retrieved later on using a URI.
"""
- file_source_uri: Optional[StrPath] = None
+ file_source_uri: StrPath | None = None
# data can be retrieved later using this URI
out_file: StrPath
@@ -2797,7 +2793,6 @@ class FileSourceModelExportStore(abc.ABC, DirectoryModelExportStore):
class BcoModelExportStore(FileSourceModelExportStore, WorkflowInvocationOnlyExportStore):
-
def __init__(self, uri, export_options: BcoExportOptions, **kwds):
self.export_options = export_options
super().__init__(uri, **kwds)
@@ -2997,7 +2992,6 @@ class ROCrateModelExportStore(DirectoryModelExportStore, WriteCrates):
class ROCrateArchiveModelExportStore(FileSourceModelExportStore, WriteCrates):
-
def _generate_output_file(self):
ro_crate = self._init_crate()
ro_crate.write(self.export_directory)
@@ -3011,7 +3005,6 @@ class ROCrateArchiveModelExportStore(FileSourceModelExportStore, WriteCrates):
class TarModelExportStore(FileSourceModelExportStore):
-
def __init__(self, uri: StrPath, gzip: bool = True, **kwds) -> None:
self.gzip = gzip
super().__init__(uri, **kwds)
@@ -3031,7 +3024,6 @@ class BagDirectoryModelExportStore(DirectoryModelExportStore):
class BagArchiveModelExportStore(FileSourceModelExportStore, BagDirectoryModelExportStore):
-
def __init__(self, uri: StrPath, bag_archiver: str = "tgz", **kwds) -> None:
# bag_archiver in tgz, zip, tar
self.bag_archiver = bag_archiver
@@ -3046,9 +3038,9 @@ def get_export_store_factory(
app,
download_format: str,
export_files=None,
- bco_export_options: Optional[BcoExportOptions] = None,
+ bco_export_options: BcoExportOptions | None = None,
user_context=None,
- ignore_errors: Optional[bool] = False,
+ ignore_errors: bool | None = False,
) -> Callable[[StrPath], FileSourceModelExportStore]:
export_store_class: type[FileSourceModelExportStore]
export_store_class_kwds = {
@@ -3088,7 +3080,7 @@ def tar_export_directory(export_directory: StrPath, out_file: StrPath, gzip: boo
store_archive.add(os.path.join(export_directory, export_path), arcname=export_path)
-def get_export_dataset_filename(name: str, ext: str, encoded_id: str, conversion_key: Optional[str]) -> str:
+def get_export_dataset_filename(name: str, ext: str, encoded_id: str, conversion_key: str | None) -> str:
"""
Builds a filename for a dataset using its name an extension.
"""
@@ -3099,7 +3091,7 @@ def get_export_dataset_filename(name: str, ext: str, encoded_id: str, conversion
return f"{base}_{encoded_id}_conversion_{conversion_key}.{ext}"
-def get_export_dataset_extra_files_dir_name(encoded_id: str, conversion_key: Optional[str]) -> str:
+def get_export_dataset_extra_files_dir_name(encoded_id: str, conversion_key: str | None) -> str:
if not conversion_key:
return f"extra_files_path_{encoded_id}"
else:
@@ -3107,7 +3099,7 @@ def get_export_dataset_extra_files_dir_name(encoded_id: str, conversion_key: Opt
def imported_store_for_metadata(
- directory: str, object_store: Optional[ObjectStore] = None
+ directory: str, object_store: ObjectStore | None = None
) -> BaseDirectoryImportModelStore:
import_options = ImportOptions(allow_dataset_object_edit=True, allow_edit=True)
import_model_store = get_import_model_store_for_directory(
@@ -3118,10 +3110,10 @@ def imported_store_for_metadata(
def source_to_import_store(
- source: Union[str, dict],
+ source: str | dict,
app: StoreAppProtocol,
- import_options: Optional[ImportOptions],
- model_store_format: Optional[ModelStoreFormat] = None,
+ import_options: ImportOptions | None,
+ model_store_format: ModelStoreFormat | None = None,
user_context=None,
) -> ModelImportStore:
galaxy_user = user_context.user if user_context else None
diff --git a/lib/galaxy/model/store/discover.py b/lib/galaxy/model/store/discover.py
index e460537e1a0..867c52ab045 100644
--- a/lib/galaxy/model/store/discover.py
+++ b/lib/galaxy/model/store/discover.py
@@ -82,7 +82,7 @@ class ModelPersistenceContext(metaclass=abc.ABCMeta):
max_discovered_files = float("inf")
discovered_file_count: int
- def get_job(self) -> Optional[galaxy.model.Job]:
+ def get_job(self) -> galaxy.model.Job | None:
return getattr(self, "job", None)
def create_dataset(
@@ -514,7 +514,7 @@ class ModelPersistenceContext(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
- def sa_session(self) -> Optional[Union["scoped_session", "SessionlessContext"]]:
+ def sa_session(self) -> Union["scoped_session", "SessionlessContext"] | None:
"""If bound to a database, return the SQL Alchemy session.
Return None otherwise.
@@ -528,16 +528,16 @@ class ModelPersistenceContext(metaclass=abc.ABCMeta):
Return None otherwise.
"""
- def get_implicit_collection_jobs_association_id(self) -> Optional[str]:
+ def get_implicit_collection_jobs_association_id(self) -> str | None:
"""No-op, no job context."""
return None
@property
@abc.abstractmethod
- def job(self) -> Optional[galaxy.model.Job]:
+ def job(self) -> galaxy.model.Job | None:
"""Return associated job object if bound to a job finish context connected to a database."""
- def override_object_store_id(self, output_name: Optional[str] = None) -> Optional[str]:
+ def override_object_store_id(self, output_name: str | None = None) -> str | None:
"""Object store ID to assign to a dataset before populating its contents."""
job = self.job
if not job:
@@ -555,12 +555,12 @@ class ModelPersistenceContext(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
- def object_store(self) -> Union[ObjectStore, None]:
+ def object_store(self) -> ObjectStore | None:
"""Return object store to use for populating discovered dataset contents."""
@property
@abc.abstractmethod
- def flush_per_n_datasets(self) -> Optional[int]:
+ def flush_per_n_datasets(self) -> int | None:
pass
@property
@@ -657,7 +657,7 @@ class SessionlessModelPersistenceContext(ModelPersistenceContext):
"""A variant of ModelPersistenceContext that persists to an export store instead of database directly."""
def __init__(
- self, object_store: Optional[ObjectStore], export_store: Optional["ModelExportStore"], working_directory: str
+ self, object_store: ObjectStore | None, export_store: Optional["ModelExportStore"], working_directory: str
) -> None:
self._permission_provider = UnusedPermissionProvider()
self._metadata_source_provider = UnusedMetadataSourceProvider()
@@ -693,11 +693,11 @@ class SessionlessModelPersistenceContext(ModelPersistenceContext):
return self._metadata_source_provider
@property
- def object_store(self) -> Union[ObjectStore, None]:
+ def object_store(self) -> ObjectStore | None:
return self._object_store
@property
- def flush_per_n_datasets(self) -> Optional[int]:
+ def flush_per_n_datasets(self) -> int | None:
return self._flush_per_n_datasets
def add_tags_to_datasets(self, datasets, tag_lists):
@@ -1015,7 +1015,7 @@ def replace_request_syntax_sugar(obj):
class DiscoveredFile(NamedTuple):
path: str
- collector: Optional[CollectorT]
+ collector: CollectorT | None
match: "JsonCollectedDatasetMatch"
def discovered_state(self, element: dict[str, Any], final_job_state="ok") -> "DiscoveredResultState":
@@ -1024,12 +1024,12 @@ class DiscoveredFile(NamedTuple):
class DiscoveredResultState(NamedTuple):
- info: Optional[str]
+ info: str | None
state: str
class DiscoveredDeferredFile(NamedTuple):
- collector: Optional[CollectorT]
+ collector: CollectorT | None
match: "JsonCollectedDatasetMatch"
def discovered_state(self, element: dict[str, Any], final_job_state="ok") -> DiscoveredResultState:
@@ -1100,7 +1100,7 @@ def discover_target_directory(dir_name, job_working_directory):
class JsonCollectedDatasetMatch:
- def __init__(self, as_dict, collector: Optional[CollectorT], filename, path=None, parent_identifiers=None):
+ def __init__(self, as_dict, collector: CollectorT | None, filename, path=None, parent_identifiers=None):
parent_identifiers = parent_identifiers or []
self.as_dict = as_dict
self.collector = collector
@@ -1199,15 +1199,15 @@ class JsonCollectedDatasetMatch:
class RegexCollectedDatasetMatch(JsonCollectedDatasetMatch):
- def __init__(self, re_match, collector: Optional[CollectorT], filename, path=None):
+ def __init__(self, re_match, collector: CollectorT | None, filename, path=None):
super().__init__(re_match.groupdict(), collector, filename, path=path)
class DiscoveredFileError(NamedTuple):
error_message: str
- collector: Optional[CollectorT]
+ collector: CollectorT | None
match: JsonCollectedDatasetMatch
- path: Optional[str] = None
+ path: str | None = None
def discovered_state(self, element: dict[str, Any], final_job_state="ok") -> DiscoveredResultState:
info = self.error_message
diff --git a/lib/galaxy/model/store/ro_crate_utils.py b/lib/galaxy/model/store/ro_crate_utils.py
index ff2914b06ef..6a7f4034a1c 100644
--- a/lib/galaxy/model/store/ro_crate_utils.py
+++ b/lib/galaxy/model/store/ro_crate_utils.py
@@ -2,7 +2,6 @@ import logging
import os
from typing import (
Any,
- Optional,
)
from rocrate.model.computationalworkflow import (
@@ -193,12 +192,12 @@ class WorkflowRunCrateProfileBuilder:
return collection_entity
- def _get_collection_additional_type(self, collection_type: Optional[str]) -> str:
+ def _get_collection_additional_type(self, collection_type: str | None) -> str:
if collection_type and "paired" in collection_type:
return "https://training.galaxyproject.org/training-material/faqs/galaxy/collections_build_list_paired.html"
return "https://training.galaxyproject.org/training-material/faqs/galaxy/collections_build_list.html"
- def _get_parameter_additional_type(self, parameter_type: Optional[str]) -> str:
+ def _get_parameter_additional_type(self, parameter_type: str | None) -> str:
if parameter_type in self.param_type_mapping:
return self.param_type_mapping[parameter_type]
return "Text"
diff --git a/lib/galaxy/model/tags.py b/lib/galaxy/model/tags.py
index fd2e56a4b5d..cf5b9ebf289 100644
--- a/lib/galaxy/model/tags.py
+++ b/lib/galaxy/model/tags.py
@@ -48,7 +48,7 @@ class TagHandler:
"""
def __init__(
- self, sa_session: Union[scoped_session, "SessionlessContext"], galaxy_session: Optional[GalaxySession] = None
+ self, sa_session: Union[scoped_session, "SessionlessContext"], galaxy_session: GalaxySession | None = None
) -> None:
self.sa_session = sa_session
# Minimum tag length.
@@ -65,7 +65,7 @@ class TagHandler:
self.item_tag_assoc_info: dict[str, ItemTagAssocInfo] = {}
self.galaxy_session = galaxy_session
- def create_tag_handler_session(self, galaxy_session: Optional[GalaxySession]):
+ def create_tag_handler_session(self, galaxy_session: GalaxySession | None):
# Creates a transient tag handler that avoids repeated flushes
if isinstance(self.sa_session, scoped_session):
return GalaxyTagHandlerSession(self.sa_session, galaxy_session=galaxy_session)
@@ -258,7 +258,7 @@ class TagHandler:
self,
user: Optional["User"],
item,
- tags_str: Optional[str],
+ tags_str: str | None,
flush=True,
):
"""Apply tags to an item."""
@@ -401,7 +401,7 @@ class TagHandler:
raw_tags = reg_exp.split(tag_str)
return self.parse_tags_list(raw_tags)
- def parse_tags_list(self, tags_list: list[str]) -> list[tuple[str, Optional[str]]]:
+ def parse_tags_list(self, tags_list: list[str]) -> list[tuple[str, str | None]]:
"""
Return a list of tag tuples (name, value) pairs derived from a list.
Method scrubs tag names and values as well.
@@ -452,13 +452,13 @@ class TagHandler:
scrubbed_tag_list.append(self._scrub_tag_name(tag))
return scrubbed_tag_list
- def _get_name_value_pair(self, tag_str) -> list[Optional[str]]:
+ def _get_name_value_pair(self, tag_str) -> list[str | None]:
"""Get name, value pair from a tag string."""
# Use regular expression to parse name, value.
if tag_str.startswith("#"):
tag_str = f"name:{tag_str[1:]}"
reg_exp = re.compile(f"[{self.key_value_separators}]")
- name_value_pair: list[Optional[str]] = list(reg_exp.split(tag_str, 1))
+ name_value_pair: list[str | None] = list(reg_exp.split(tag_str, 1))
# Add empty slot if tag does not have value.
if len(name_value_pair) < 2:
name_value_pair.append(None)
@@ -468,7 +468,7 @@ class TagHandler:
class GalaxyTagHandler(TagHandler):
_item_tag_assoc_info: dict[str, ItemTagAssocInfo] = {}
- def __init__(self, sa_session: scoped_session, galaxy_session: Optional[GalaxySession] = None):
+ def __init__(self, sa_session: scoped_session, galaxy_session: GalaxySession | None = None):
super().__init__(sa_session, galaxy_session=galaxy_session)
if not GalaxyTagHandler._item_tag_assoc_info:
GalaxyTagHandler.init_tag_associations()
@@ -515,7 +515,7 @@ class GalaxyTagHandler(TagHandler):
class GalaxyTagHandlerSession(GalaxyTagHandler):
"""Like GalaxyTagHandler, but avoids one flush per created tag."""
- def __init__(self, sa_session: scoped_session, galaxy_session: Optional[GalaxySession]):
+ def __init__(self, sa_session: scoped_session, galaxy_session: GalaxySession | None):
super().__init__(sa_session, galaxy_session)
self.created_tags: dict[str, Tag] = {}
diff --git a/lib/galaxy/model/tool_shed_install/__init__.py b/lib/galaxy/model/tool_shed_install/__init__.py
index 37ed3e8e59b..674ec9af6db 100644
--- a/lib/galaxy/model/tool_shed_install/__init__.py
+++ b/lib/galaxy/model/tool_shed_install/__init__.py
@@ -5,7 +5,6 @@ from datetime import datetime
from enum import Enum
from typing import (
Any,
- Optional,
)
from sqlalchemy import (
@@ -49,7 +48,7 @@ mapper_registry = registry()
class HasToolBox(common_util.HasToolShedRegistry, Protocol):
@property
- def tool_dependency_dir(self) -> Optional[str]: ...
+ def tool_dependency_dir(self) -> str | None: ...
@property
def toolbox(self) -> AbstractToolBox: ...
@@ -74,19 +73,19 @@ class ToolShedRepository(Base):
update_time: Mapped[datetime] = mapped_column(DateTime, default=now, onupdate=now, nullable=True)
tool_shed: Mapped[str] = mapped_column(TrimmedString(255), index=True, nullable=True)
name: Mapped[str] = mapped_column(TrimmedString(255), index=True, nullable=True)
- description: Mapped[Optional[str]] = mapped_column(TEXT)
+ description: Mapped[str | None] = mapped_column(TEXT)
owner: Mapped[str] = mapped_column(TrimmedString(255), index=True, nullable=True)
installed_changeset_revision: Mapped[str] = mapped_column(TrimmedString(255), nullable=True)
changeset_revision: Mapped[str] = mapped_column(TrimmedString(255), index=True, nullable=True)
- ctx_rev: Mapped[Optional[str]] = mapped_column(TrimmedString(10))
+ ctx_rev: Mapped[str | None] = mapped_column(TrimmedString(10))
metadata_ = Column("metadata", MutableJSONType, nullable=True)
- includes_datatypes: Mapped[Optional[bool]] = mapped_column(Boolean, index=True, default=False)
+ includes_datatypes: Mapped[bool | None] = mapped_column(Boolean, index=True, default=False)
tool_shed_status = Column(MutableJSONType, nullable=True)
- deleted: Mapped[Optional[bool]] = mapped_column(Boolean, index=True, default=False)
- uninstalled: Mapped[Optional[bool]] = mapped_column(Boolean, default=False)
- dist_to_shed: Mapped[Optional[bool]] = mapped_column(Boolean, default=False)
- status: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- error_message: Mapped[Optional[str]] = mapped_column(TEXT)
+ deleted: Mapped[bool | None] = mapped_column(Boolean, index=True, default=False)
+ uninstalled: Mapped[bool | None] = mapped_column(Boolean, default=False)
+ dist_to_shed: Mapped[bool | None] = mapped_column(Boolean, default=False)
+ status: Mapped[str | None] = mapped_column(TrimmedString(255))
+ error_message: Mapped[str | None] = mapped_column(TEXT)
tool_versions = relationship("ToolVersion", back_populates="tool_shed_repository")
tool_dependencies = relationship(
"ToolDependency", order_by="ToolDependency.name", back_populates="tool_shed_repository"
@@ -183,7 +182,7 @@ class ToolShedRepository(Base):
self.status = status
self.error_message = error_message
- def as_dict(self, value_mapper: Optional[dict[str, Callable]] = None) -> dict[str, Any]:
+ def as_dict(self, value_mapper: dict[str, Callable] | None = None) -> dict[str, Any]:
return self.to_dict(view="element", value_mapper=value_mapper)
@property
@@ -526,7 +525,7 @@ class ToolShedRepository(Base):
return asbool(self.tool_shed_status.get("revision_update", False))
return False
- def to_dict(self, view="collection", value_mapper: Optional[dict[str, Callable]] = None) -> dict[str, Any]:
+ def to_dict(self, view="collection", value_mapper: dict[str, Callable] | None = None) -> dict[str, Any]:
if value_mapper is None:
value_mapper = {}
rval = {}
@@ -649,10 +648,10 @@ class RepositoryRepositoryDependencyAssociation(Base):
__tablename__ = "repository_repository_dependency_association"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
- tool_shed_repository_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tool_shed_repository.id"), index=True)
- repository_dependency_id: Mapped[Optional[int]] = mapped_column(ForeignKey("repository_dependency.id"), index=True)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
+ tool_shed_repository_id: Mapped[int | None] = mapped_column(ForeignKey("tool_shed_repository.id"), index=True)
+ repository_dependency_id: Mapped[int | None] = mapped_column(ForeignKey("repository_dependency.id"), index=True)
repository = relationship("ToolShedRepository", back_populates="required_repositories")
repository_dependency = relationship("RepositoryDependency")
@@ -665,8 +664,8 @@ class RepositoryDependency(Base):
__tablename__ = "repository_dependency"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
tool_shed_repository_id: Mapped[int] = mapped_column(
ForeignKey("tool_shed_repository.id"), index=True, nullable=False
)
@@ -680,16 +679,16 @@ class ToolDependency(Base):
__tablename__ = "tool_dependency"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
tool_shed_repository_id: Mapped[int] = mapped_column(
ForeignKey("tool_shed_repository.id"), index=True, nullable=False
)
name: Mapped[str] = mapped_column(TrimmedString(255), nullable=True)
version: Mapped[str] = mapped_column(TEXT, nullable=True)
- type: Mapped[Optional[str]] = mapped_column(TrimmedString(40))
+ type: Mapped[str | None] = mapped_column(TrimmedString(40))
status: Mapped[str] = mapped_column(TrimmedString(255), nullable=False)
- error_message: Mapped[Optional[str]] = mapped_column(TEXT)
+ error_message: Mapped[str | None] = mapped_column(TEXT)
tool_shed_repository = relationship("ToolShedRepository", back_populates="tool_dependencies")
# converting this one to Enum breaks the tool shed tests,
@@ -740,7 +739,7 @@ class ToolDependency(Base):
def in_error_state(self):
return self.status == self.installation_status.ERROR
- def installation_directory(self, app: HasToolBox) -> Optional[str]:
+ def installation_directory(self, app: HasToolBox) -> str | None:
if self.type == "package":
assert app.tool_dependency_dir
return os.path.join(
@@ -772,10 +771,10 @@ class ToolVersion(Base, Dictifiable):
__tablename__ = "tool_version"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
- tool_id: Mapped[Optional[str]] = mapped_column(String(255))
- tool_shed_repository_id: Mapped[Optional[int]] = mapped_column(
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
+ tool_id: Mapped[str | None] = mapped_column(String(255))
+ tool_shed_repository_id: Mapped[int | None] = mapped_column(
ForeignKey("tool_shed_repository.id"), index=True, nullable=True
)
parent_tool_association = relationship(
diff --git a/lib/galaxy/model/tool_shed_install/mapping.py b/lib/galaxy/model/tool_shed_install/mapping.py
index 2406fb3a28d..8f8bb76cfbb 100644
--- a/lib/galaxy/model/tool_shed_install/mapping.py
+++ b/lib/galaxy/model/tool_shed_install/mapping.py
@@ -1,7 +1,6 @@
from typing import (
Any,
TYPE_CHECKING,
- Union,
)
from galaxy.model import tool_shed_install as install_model
@@ -15,7 +14,7 @@ if TYPE_CHECKING:
metadata = mapper_registry.metadata
-def init(url: str, engine_options: Union[dict[str, Any], None] = None, create_tables: bool = False) -> ModelMapping:
+def init(url: str, engine_options: dict[str, Any] | None = None, create_tables: bool = False) -> ModelMapping:
engine = build_engine(url, engine_options)
if create_tables:
create_database_objects(engine)
diff --git a/lib/galaxy/model/unittest_utils/data_app.py b/lib/galaxy/model/unittest_utils/data_app.py
index 2eb7e78bf3e..18818c3198f 100644
--- a/lib/galaxy/model/unittest_utils/data_app.py
+++ b/lib/galaxy/model/unittest_utils/data_app.py
@@ -10,7 +10,6 @@ import os
import shutil
import tempfile
from types import SimpleNamespace
-from typing import Optional
from galaxy import (
model,
@@ -97,7 +96,7 @@ class GalaxyDataTestApp:
security_agent: GalaxyRBACAgent
file_sources: ConfiguredFileSources = NullConfiguredFileSources()
- def __init__(self, config: Optional[GalaxyDataTestConfig] = None, **kwd):
+ def __init__(self, config: GalaxyDataTestConfig | None = None, **kwd):
config = config or GalaxyDataTestConfig(**kwd)
self.config = config
self.security = config.security
diff --git a/lib/galaxy/model/unittest_utils/model_testing_utils.py b/lib/galaxy/model/unittest_utils/model_testing_utils.py
index 4f2be899aec..442f124a46a 100644
--- a/lib/galaxy/model/unittest_utils/model_testing_utils.py
+++ b/lib/galaxy/model/unittest_utils/model_testing_utils.py
@@ -5,9 +5,6 @@ from collections.abc import (
Iterator,
)
from contextlib import contextmanager
-from typing import (
- Optional,
-)
import pytest
from sqlalchemy import (
@@ -253,7 +250,7 @@ def _generate_unique_database_name() -> str:
return f"galaxytest_{uuid.uuid4().hex}"
-def _get_connection_url() -> Optional[str]:
+def _get_connection_url() -> str | None:
return os.environ.get("GALAXY_TEST_DBURI")
diff --git a/lib/galaxy/navigation/components.py b/lib/galaxy/navigation/components.py
index 9bd00cc8f77..9a523d19af0 100644
--- a/lib/galaxy/navigation/components.py
+++ b/lib/galaxy/navigation/components.py
@@ -4,8 +4,6 @@ import string
from enum import Enum
from typing import (
NamedTuple,
- Optional,
- Union,
)
from galaxy.util.bunch import Bunch
@@ -58,7 +56,7 @@ class Target(metaclass=abc.ABCMeta):
class SelectorTemplate(Target):
def __init__(
self,
- selector: Union[str, list[str]],
+ selector: str | list[str],
selector_type: str,
children=None,
kwds=None,
@@ -181,7 +179,7 @@ class SelectorTemplate(Target):
assert re.compile(r"\.\w+").match(selector)
return selector[1:]
- def resolve_component_locator(self, path: Optional[str] = None) -> LocatorT:
+ def resolve_component_locator(self, path: str | None = None) -> LocatorT:
if path:
return self[path].component_locator
else:
@@ -222,7 +220,7 @@ class Text(Target):
return LocatorT(ComponentBy.TEXT, self.text)
-HasText = Union[Label, Text]
+HasText = Label | Text
CALL_ARGUMENTS_RE = re.compile(r"(?P[^.(]*)(\((?P[^)]+)\))?(?:\.(?P.*))?")
@@ -246,11 +244,11 @@ class Component:
else:
raise Exception(f"No _ selector for [{self}]")
- def resolve_component_locator(self, path: Optional[str] = None) -> LocatorT:
+ def resolve_component_locator(self, path: str | None = None) -> LocatorT:
if not path:
return self._selectors["_"].resolve_component_locator()
- def arguments() -> tuple[str, Optional[dict[str, str]], Optional[str]]:
+ def arguments() -> tuple[str, dict[str, str] | None, str | None]:
assert path
if match := CALL_ARGUMENTS_RE.match(path):
component_name = match.group("SUBCOMPONENT")
diff --git a/lib/galaxy/objectstore/__init__.py b/lib/galaxy/objectstore/__init__.py
index 74c73b71229..3e9a56ec216 100644
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -14,13 +14,9 @@ import threading
import time
from typing import (
Any,
- Dict,
- List,
+ Literal,
NamedTuple,
Optional,
- Set,
- Tuple,
- Type,
TYPE_CHECKING,
)
from uuid import uuid4
@@ -28,7 +24,6 @@ from uuid import uuid4
import yaml
from pydantic import BaseModel
from typing_extensions import (
- Literal,
Protocol,
)
@@ -80,7 +75,7 @@ USER_OBJECTS_SCHEME = "user_objects://"
log = logging.getLogger(__name__)
-def is_user_object_store(object_store_id: Optional[str]) -> bool:
+def is_user_object_store(object_store_id: str | None) -> bool:
return object_store_id is not None and object_store_id.startswith(USER_OBJECTS_SCHEME)
@@ -347,7 +342,7 @@ class ObjectStore(metaclass=abc.ABCMeta):
"""
@abc.abstractmethod
- def get_concrete_store_badges(self, obj) -> List[BadgeDict]:
+ def get_concrete_store_badges(self, obj) -> list[BadgeDict]:
"""Return a list of dictified badges summarizing the object store configuration."""
@abc.abstractmethod
@@ -367,12 +362,12 @@ class ObjectStore(metaclass=abc.ABCMeta):
"""Return True if this object store respects object_store_id and allow selection of this."""
return False
- def validate_selected_object_store_id(self, user, object_store_id: Optional[str]) -> Optional[str]:
+ def validate_selected_object_store_id(self, user, object_store_id: str | None) -> str | None:
if object_store_id and not self.object_store_allows_id_selection():
return "The current configuration doesn't allow selecting preferred object stores."
return None
- def object_store_ids_allowing_selection(self) -> List[str]:
+ def object_store_ids_allowing_selection(self) -> list[str]:
"""Return a non-emtpy list of allowed selectable object store IDs during creation."""
return []
@@ -394,12 +389,12 @@ class ObjectStore(metaclass=abc.ABCMeta):
raise NotImplementedError()
@abc.abstractmethod
- def cache_targets(self) -> List[CacheTarget]:
+ def cache_targets(self) -> list[CacheTarget]:
"""Return a list of CacheTargets used by this object store."""
raise NotImplementedError()
@abc.abstractmethod
- def to_dict(self) -> Dict[str, Any]:
+ def to_dict(self) -> dict[str, Any]:
raise NotImplementedError()
@abc.abstractmethod
@@ -684,7 +679,7 @@ class BaseObjectStore(ObjectStore):
def get_concrete_store_description_markdown(self, obj):
return self._invoke("get_concrete_store_description_markdown", obj)
- def get_concrete_store_badges(self, obj) -> List[BadgeDict]:
+ def get_concrete_store_badges(self, obj) -> list[BadgeDict]:
return self._invoke("get_concrete_store_badges", obj)
def get_store_usage_percent(self):
@@ -696,7 +691,7 @@ class BaseObjectStore(ObjectStore):
def is_private(self, obj) -> bool:
return self._invoke("is_private", obj)
- def cache_targets(self) -> List[CacheTarget]:
+ def cache_targets(self) -> list[CacheTarget]:
return []
@classmethod
@@ -731,8 +726,8 @@ class ConcreteObjectStore(BaseObjectStore):
persisted, not how a file is routed to a persistence source.
"""
- badges: List[StoredBadgeDict]
- device_id: Optional[str] = None
+ badges: list[StoredBadgeDict]
+ device_id: str | None = None
cloud: bool = False
def __init__(self, config, config_dict=None, **kwargs):
@@ -792,7 +787,7 @@ class ConcreteObjectStore(BaseObjectStore):
object_expires_after_days=self.object_expires_after_days,
)
- def _get_concrete_store_badges(self, obj) -> List[BadgeDict]:
+ def _get_concrete_store_badges(self, obj) -> list[BadgeDict]:
return serialize_badges(
self.badges,
self.galaxy_enable_quotas and self.quota_enabled,
@@ -814,10 +809,10 @@ class ConcreteObjectStore(BaseObjectStore):
return self.private
@property
- def cache_target(self) -> Optional[CacheTarget]:
+ def cache_target(self) -> CacheTarget | None:
return None
- def cache_targets(self) -> List[CacheTarget]:
+ def cache_targets(self) -> list[CacheTarget]:
cache_target = self.cache_target
return [cache_target] if cache_target is not None else []
@@ -1170,7 +1165,7 @@ class NestedObjectStore(BaseObjectStore):
Example: DistributedObjectStore, HierarchicalObjectStore
"""
- backends: Dict
+ backends: dict
def __init__(self, config, config_xml=None):
"""Extend `ObjectStore`'s constructor."""
@@ -1192,7 +1187,7 @@ class NestedObjectStore(BaseObjectStore):
objectstore = random.choice(list(self.backends.values()))
return objectstore.create(obj, **kwargs)
- def cache_targets(self) -> List[CacheTarget]:
+ def cache_targets(self) -> list[CacheTarget]:
cache_targets = []
for backend in self.backends.values():
cache_targets.extend(backend.cache_targets())
@@ -1266,7 +1261,7 @@ class NestedObjectStore(BaseObjectStore):
def _get_concrete_store_description_markdown(self, obj):
return self._call_method("_get_concrete_store_description_markdown", obj, None, False)
- def _get_concrete_store_badges(self, obj) -> List[BadgeDict]:
+ def _get_concrete_store_badges(self, obj) -> list[BadgeDict]:
return self._call_method("_get_concrete_store_badges", obj, [], False)
def _is_private(self, obj) -> bool:
@@ -1310,7 +1305,7 @@ class NestedObjectStore(BaseObjectStore):
return default
-def user_object_store_configuration_to_config_dict(object_store_config: ObjectStoreConfiguration, id) -> Dict[str, Any]:
+def user_object_store_configuration_to_config_dict(object_store_config: ObjectStoreConfiguration, id) -> dict[str, Any]:
# convert a pydantic model describing a user object store into a config dict ready to be
# slotted into a distributed job runner or stand alone.
dynamic_object_store_as_dict = object_store_config.model_dump()
@@ -1330,13 +1325,13 @@ class DistributedObjectStore(NestedObjectStore):
with weighting.
"""
- backends: Dict[str, Any] # BaseObjectStore or ConcreteObjectStore?
+ backends: dict[str, Any] # BaseObjectStore or ConcreteObjectStore?
store_type = "distributed"
_quota_source_map: Optional["QuotaSourceMap"]
_device_source_map: Optional["DeviceSourceMap"]
def __init__(
- self, config, config_dict, fsmon=False, user_object_store_resolver: Optional[UserObjectStoreResolver] = None
+ self, config, config_dict, fsmon=False, user_object_store_resolver: UserObjectStoreResolver | None = None
):
"""
:type config: object
@@ -1400,7 +1395,7 @@ class DistributedObjectStore(NestedObjectStore):
else:
backends_root = config_xml.find("backends")
- backends: List[Dict[str, Any]] = []
+ backends: list[dict[str, Any]] = []
config_dict = {
"search_for_missing": asbool(backends_root.get("search_for_missing", True)),
"global_max_percent_full": float(backends_root.get("maxpctfull", 0)),
@@ -1434,7 +1429,7 @@ class DistributedObjectStore(NestedObjectStore):
config,
config_xml,
fsmon=False,
- user_object_store_resolver: Optional[UserObjectStoreResolver] = None,
+ user_object_store_resolver: UserObjectStoreResolver | None = None,
**kwd,
):
legacy = False
@@ -1455,11 +1450,11 @@ class DistributedObjectStore(NestedObjectStore):
config_dict = clazz.parse_xml(config_xml, legacy=legacy)
return clazz(config, config_dict, fsmon=fsmon, user_object_store_resolver=user_object_store_resolver)
- def to_dict(self, object_store_uris: Optional[Set[str]] = None) -> Dict[str, Any]:
+ def to_dict(self, object_store_uris: set[str] | None = None) -> dict[str, Any]:
as_dict = super().to_dict()
as_dict["global_max_percent_full"] = self.global_max_percent_full
as_dict["search_for_missing"] = self.search_for_missing
- backends: List[Dict[str, Any]] = []
+ backends: list[dict[str, Any]] = []
for backend_id, backend in self.backends.items():
backend_as_dict = backend.to_dict()
backend_as_dict["id"] = backend_id
@@ -1533,8 +1528,7 @@ class DistributedObjectStore(NestedObjectStore):
return self._resolve_backend(object_store_id)
def _call_method(self, method, obj, default, default_is_exception, **kwargs):
- object_store_id = self.__get_store_id_for(obj, **kwargs)
- if object_store_id is not None:
+ if (object_store_id := self.__get_store_id_for(obj, **kwargs)) is not None:
return self._resolve_backend(object_store_id).__getattribute__(method)(obj, **kwargs)
if default_is_exception:
raise default(
@@ -1637,7 +1631,7 @@ class DistributedObjectStore(NestedObjectStore):
"""Return True if this object store respects object_store_id and allow selection of this."""
return self.allow_user_selection
- def validate_selected_object_store_id(self, user, object_store_id: Optional[str]) -> Optional[str]:
+ def validate_selected_object_store_id(self, user, object_store_id: str | None) -> str | None:
parent_check = super().validate_selected_object_store_id(user, object_store_id)
if parent_check or object_store_id is None:
return parent_check
@@ -1655,7 +1649,7 @@ class DistributedObjectStore(NestedObjectStore):
return "Supplied object store id is not an allowed object store selection"
return None
- def object_store_ids_allowing_selection(self) -> List[str]:
+ def object_store_ids_allowing_selection(self) -> list[str]:
"""Return a non-empty list of allowed selectable object store IDs during creation."""
return self.user_selection_allowed
@@ -1672,7 +1666,7 @@ class HierarchicalObjectStore(NestedObjectStore):
When creating objects only the first store is used.
"""
- backends: Dict[int, BaseObjectStore]
+ backends: dict[int, BaseObjectStore]
store_type = "hierarchical"
def __init__(self, config, config_dict, fsmon=False):
@@ -1754,7 +1748,7 @@ class HierarchicalObjectStore(NestedObjectStore):
return quota_source_map
-def serialize_static_object_store_config(object_store: ObjectStore, object_store_uris: Set[str]) -> Dict[str, Any]:
+def serialize_static_object_store_config(object_store: ObjectStore, object_store_uris: set[str]) -> dict[str, Any]:
"""Serialize a static object store configuration for database-less serialization.
The database-less part here comes from the fact these are used in job directories
@@ -1773,26 +1767,26 @@ def serialize_static_object_store_config(object_store: ObjectStore, object_store
class QuotaModel(BaseModel):
- source: Optional[str] = None
+ source: str | None = None
enabled: bool
class ConcreteObjectStoreModel(BaseModel):
- object_store_id: Optional[str] = None
+ object_store_id: str | None = None
private: bool
- name: Optional[str] = None
- description: Optional[str] = None
+ name: str | None = None
+ description: str | None = None
quota: QuotaModel
- badges: List[BadgeDict]
- device: Optional[str] = None
- object_expires_after_days: Optional[int] = None
+ badges: list[BadgeDict]
+ device: str | None = None
+ object_expires_after_days: int | None = None
def type_to_object_store_class(
- store: str, fsmon: bool = False, user_object_store_resolver: Optional[UserObjectStoreResolver] = None
-) -> Tuple[Type[BaseObjectStore], Dict[str, Any]]:
- objectstore_class: Type[BaseObjectStore]
- objectstore_constructor_kwds: Dict[str, Any] = {}
+ store: str, fsmon: bool = False, user_object_store_resolver: UserObjectStoreResolver | None = None
+) -> tuple[type[BaseObjectStore], dict[str, Any]]:
+ objectstore_class: type[BaseObjectStore]
+ objectstore_constructor_kwds: dict[str, Any] = {}
if store == "disk":
objectstore_class = DiskObjectStore
elif store == "boto3":
@@ -1869,7 +1863,7 @@ def build_object_store_from_config(
config_xml=None,
config_dict=None,
disable_process_management=False,
- user_object_store_resolver: Optional[UserObjectStoreResolver] = None,
+ user_object_store_resolver: UserObjectStoreResolver | None = None,
):
"""
Invoke the appropriate object store.
@@ -1991,7 +1985,7 @@ def config_to_dict(config):
class QuotaSourceInfo(NamedTuple):
- label: Optional[str]
+ label: str | None
use: bool
@@ -2000,7 +1994,7 @@ class DeviceSourceMap:
self.default_device_id = device_id
self.backends = {}
- def get_device_id(self, object_store_id: str) -> Optional[str]:
+ def get_device_id(self, object_store_id: str) -> str | None:
if object_store_id in self.backends:
device_map = self.backends.get(object_store_id)
if device_map:
@@ -2019,7 +2013,7 @@ class QuotaSourceMap:
self.backends = {}
self._labels = None
- def get_quota_source_info(self, object_store_id: Optional[str]) -> QuotaSourceInfo:
+ def get_quota_source_info(self, object_store_id: str | None) -> QuotaSourceInfo:
if object_store_id in self.backends:
return self.backends[object_store_id].get_quota_source_info(object_store_id)
elif is_user_object_store(object_store_id):
@@ -2062,7 +2056,7 @@ class QuotaSourceMap:
return pairs
def ids_per_quota_source(self, include_default_quota_source=False):
- quota_sources: Dict[Optional[str], List[str]] = {}
+ quota_sources: dict[str | None, list[str]] = {}
for object_id, quota_source_label in self.get_id_to_source_pairs(
include_default_quota_source=include_default_quota_source
):
@@ -2124,7 +2118,7 @@ def persist_extra_files(
object_store: ObjectStore,
src_extra_files_path: str,
primary_data: "DatasetInstance",
- extra_files_path_name: Optional[str] = None,
+ extra_files_path_name: str | None = None,
) -> None:
assert primary_data.dataset is not None
if not primary_data.dataset.purged and os.path.exists(src_extra_files_path):
diff --git a/lib/galaxy/objectstore/_caching_base.py b/lib/galaxy/objectstore/_caching_base.py
index f156d5cfabe..8c980c2a4f8 100644
--- a/lib/galaxy/objectstore/_caching_base.py
+++ b/lib/galaxy/objectstore/_caching_base.py
@@ -5,8 +5,6 @@ from contextlib import contextmanager
from datetime import datetime
from typing import (
Any,
- Dict,
- Optional,
)
from galaxy.exceptions import (
@@ -30,12 +28,12 @@ log = logging.getLogger(__name__)
class CachingConcreteObjectStore(ConcreteObjectStore):
staging_path: str
- extra_dirs: Dict[str, str]
+ extra_dirs: dict[str, str]
config: Any
cache_updated_data: bool
enable_cache_monitor: bool
cache_size: int
- cache_monitor: Optional[InProcessCacheMonitor] = None
+ cache_monitor: InProcessCacheMonitor | None = None
cache_monitor_interval: int
def _ensure_staging_path_writable(self):
@@ -198,7 +196,7 @@ class CachingConcreteObjectStore(ConcreteObjectStore):
self._push_to_storage(rel_path, from_string="")
return self
- def _caching_allowed(self, rel_path: str, remote_size: Optional[int] = None) -> bool:
+ def _caching_allowed(self, rel_path: str, remote_size: int | None = None) -> bool:
if remote_size is None:
remote_size = self._get_remote_size(rel_path)
if not self.cache_target.fits_in_cache(remote_size):
diff --git a/lib/galaxy/objectstore/badges.py b/lib/galaxy/objectstore/badges.py
index 5d1fae30d90..f115263de4f 100644
--- a/lib/galaxy/objectstore/badges.py
+++ b/lib/galaxy/objectstore/badges.py
@@ -1,14 +1,9 @@
from typing import (
Any,
- Dict,
- List,
- Optional,
- Set,
- Union,
+ Literal,
)
from typing_extensions import (
- Literal,
NotRequired,
TypedDict,
)
@@ -28,26 +23,17 @@ AdminBadgeT = Literal[
]
# All badges - so AdminBadgeT plus Galaxy specifiable badges.
-BadgeT = Union[
- AdminBadgeT,
- Literal[
- "cloud",
- "quota",
- "no_quota",
- "restricted",
- "user_defined",
- ],
-]
+BadgeT = AdminBadgeT | Literal["cloud", "quota", "no_quota", "restricted", "user_defined"]
class BadgeSpecDict(TypedDict):
"""Describe badges that can be set by Galaxy admins."""
type: AdminBadgeT
- conflicts: List[AdminBadgeT]
+ conflicts: list[AdminBadgeT]
-BADGE_SPECIFICATION: List[BadgeSpecDict] = [
+BADGE_SPECIFICATION: list[BadgeSpecDict] = [
{"type": "faster", "conflicts": ["slower"]},
{"type": "slower", "conflicts": ["faster"]},
{"type": "short_term", "conflicts": []},
@@ -59,26 +45,26 @@ BADGE_SPECIFICATION: List[BadgeSpecDict] = [
{"type": "less_stable", "conflicts": ["more_stable"]},
]
-KNOWN_BADGE_TYPES: List[AdminBadgeT] = [s["type"] for s in BADGE_SPECIFICATION]
-BADGE_SPECIFICATION_BY_TYPE: Dict[AdminBadgeT, BadgeSpecDict] = {s["type"]: s for s in BADGE_SPECIFICATION}
+KNOWN_BADGE_TYPES: list[AdminBadgeT] = [s["type"] for s in BADGE_SPECIFICATION]
+BADGE_SPECIFICATION_BY_TYPE: dict[AdminBadgeT, BadgeSpecDict] = {s["type"]: s for s in BADGE_SPECIFICATION}
class BadgeDict(TypedDict):
type: BadgeT
- message: Optional[str]
+ message: str | None
source: BadgeSourceT
class StoredBadgeDict(TypedDict):
type: AdminBadgeT
- message: NotRequired[Optional[str]]
+ message: NotRequired[str | None]
-def read_badges(config_dict: Dict[str, Any]) -> List[StoredBadgeDict]:
+def read_badges(config_dict: dict[str, Any]) -> list[StoredBadgeDict]:
raw_badges = config_dict.get("badges") or []
- badges: List[StoredBadgeDict] = []
- badge_types: Set[str] = set()
- badge_conflicts: Dict[str, str] = {}
+ badges: list[StoredBadgeDict] = []
+ badge_types: set[str] = set()
+ badge_conflicts: dict[str, str] = {}
for badge in raw_badges:
# when recovering serialized badges, skip ones that are set by Galaxy
badge_source = badge.get("source")
@@ -104,15 +90,15 @@ def read_badges(config_dict: Dict[str, Any]) -> List[StoredBadgeDict]:
def serialize_badges(
- stored_badges: List[StoredBadgeDict], quota_enabled: bool, private: bool, user_defined: bool, cloud: bool
-) -> List[BadgeDict]:
+ stored_badges: list[StoredBadgeDict], quota_enabled: bool, private: bool, user_defined: bool, cloud: bool
+) -> list[BadgeDict]:
"""Produce blended, unified list of badges for target object store entity.
Combine more free form admin information stored about badges with Galaxy tracked
information (quota and access restriction information) to produce a unified list
of badges to be consumed via the API.
"""
- badge_dicts: List[BadgeDict] = []
+ badge_dicts: list[BadgeDict] = []
for badge in stored_badges:
badge_dict: BadgeDict = {
"source": "admin",
diff --git a/lib/galaxy/objectstore/caching.py b/lib/galaxy/objectstore/caching.py
index a7b2507cbce..d27321f83b7 100644
--- a/lib/galaxy/objectstore/caching.py
+++ b/lib/galaxy/objectstore/caching.py
@@ -5,11 +5,6 @@ import os
import threading
import time
from math import inf
-from typing import (
- List,
- Optional,
- Tuple,
-)
from typing_extensions import NamedTuple
@@ -25,7 +20,7 @@ log = logging.getLogger(__name__)
ONE_GIGA_BYTE = 1024 * 1024 * 1024
-FileListT = List[Tuple[time.struct_time, str, int]]
+FileListT = list[tuple[time.struct_time, str, int]]
class CacheTarget(NamedTuple):
@@ -48,7 +43,7 @@ class CacheTarget(NamedTuple):
return f"{self.limit} percent of {self.size} gigabytes"
-def check_caches(targets: List[CacheTarget]):
+def check_caches(targets: list[CacheTarget]):
for target in targets:
check_cache(target)
@@ -61,8 +56,7 @@ def check_cache(cache_target: CacheTarget):
# Initiate cleaning once we reach cache_monitor_cache_limit percentage of the defined cache size?
# Convert GBs to bytes for comparison
cache_size_in_gb = cache_target.size * ONE_GIGA_BYTE
- cache_limit = cache_size_in_gb * cache_target.limit
- if total_size > cache_limit:
+ if total_size > (cache_limit := cache_size_in_gb * cache_target.limit):
log.debug(
"Initiating cache cleaning: current cache size: %s; clean until smaller than: %s",
nice_size(total_size),
@@ -105,7 +99,7 @@ def _clean_cache(file_list: FileListT, delete_this_much: float) -> None:
return
-def _get_cache_size_files(cache_path) -> Tuple[int, FileListT]:
+def _get_cache_size_files(cache_path) -> tuple[int, FileListT]:
"""Returns cache size and cache files.
For each file, we get last access time, file path, and file size.
@@ -155,7 +149,7 @@ def configured_cache_size(config, config_dict) -> int:
return cache_size
-def enable_cache_monitor(config, config_dict) -> Tuple[bool, int]:
+def enable_cache_monitor(config, config_dict) -> tuple[bool, int]:
cache_config_dict = config_dict.get("cache") or {}
default_interval = getattr(config, "object_store_cache_monitor_interval", 600)
interval = cache_config_dict.get("monitor_interval") or default_interval
@@ -176,7 +170,7 @@ def enable_cache_monitor(config, config_dict) -> Tuple[bool, int]:
class InProcessCacheMonitor:
- def __init__(self, cache_target: CacheTarget, interval: int = 30, initial_sleep: Optional[int] = 2):
+ def __init__(self, cache_target: CacheTarget, interval: int = 30, initial_sleep: int | None = 2):
# This Event object is initialized to False
# It is set to True in shutdown(), causing
# the cache monitor thread to return/terminate
diff --git a/lib/galaxy/objectstore/cloud.py b/lib/galaxy/objectstore/cloud.py
index 811fd4d2b69..b1baf80dc7a 100644
--- a/lib/galaxy/objectstore/cloud.py
+++ b/lib/galaxy/objectstore/cloud.py
@@ -173,10 +173,7 @@ class Cloud(CachingConcreteObjectStore, UsesAxel):
raise Exception(msg)
if len(missing_config) > 0:
- msg = (
- f"The following configuration required for {provider} cloud backend "
- f"are missing: {missing_config}"
- )
+ msg = f"The following configuration required for {provider} cloud backend are missing: {missing_config}"
log.error(msg)
raise Exception(msg)
else:
diff --git a/lib/galaxy/objectstore/pithos.py b/lib/galaxy/objectstore/pithos.py
index 3c1f927f238..2e1bfba3862 100644
--- a/lib/galaxy/objectstore/pithos.py
+++ b/lib/galaxy/objectstore/pithos.py
@@ -117,8 +117,7 @@ class PithosObjectStore(CachingConcreteObjectStore):
def _authenticate(self):
auth = self.config_dict["auth"]
url, token = auth["url"], auth["token"]
- ca_certs = auth.get("ca_certs")
- if ca_certs:
+ if ca_certs := auth.get("ca_certs"):
utils.https.patch_with_certs(ca_certs)
elif auth.get("ignore_ssl").lower() in ("true", "yes", "on"):
utils.https.patch_ignore_ssl()
diff --git a/lib/galaxy/objectstore/rucio.py b/lib/galaxy/objectstore/rucio.py
index 5a6696f9a10..6609ff69af3 100644
--- a/lib/galaxy/objectstore/rucio.py
+++ b/lib/galaxy/objectstore/rucio.py
@@ -2,7 +2,6 @@ import hashlib
import logging
import os
import shutil
-from typing import Optional
try:
import rucio.common
@@ -143,7 +142,7 @@ def parse_config_xml(config_xml):
class RucioBroker:
def __init__(self, rucio_object_store):
self._temp_file_name = None
- self.rucio_config_path: Optional[str] = None
+ self.rucio_config_path: str | None = None
self.config = rucio_object_store.rucio_config
self.extra_dirs = rucio_object_store.extra_dirs
self.upload_scheme = self.config["upload_scheme"]
@@ -163,11 +162,11 @@ class RucioBroker:
rucio_config_path = os.path.join(temp_directory, "rucio.cfg")
with open(rucio_config_path, "w") as f:
f.write(f"""[client]
-rucio_host = {self.config['host']}
-auth_host = {self.config['auth_host']}
-account = {self.config['account']}
-auth_type = {self.config['auth_type']}
-username = {self.config['username']}
+rucio_host = {self.config["host"]}
+auth_host = {self.config["auth_host"]}
+account = {self.config["account"]}
+auth_type = {self.config["auth_type"]}
+username = {self.config["username"]}
{key_for_pass} = {self.config[key_for_pass]}
""")
self.rucio_config_path = rucio_config_path
@@ -426,7 +425,7 @@ class RucioObjectStore(CachingConcreteObjectStore):
log.debug("rucio _size: %s", rel_path)
if self._in_cache(rel_path):
- size: Optional[int] = None
+ size: int | None = None
try:
size = os.path.getsize(self._get_cache_path(rel_path))
except OSError as ex:
diff --git a/lib/galaxy/objectstore/s3_boto3.py b/lib/galaxy/objectstore/s3_boto3.py
index 6e57c7982ed..f6850fd5be0 100644
--- a/lib/galaxy/objectstore/s3_boto3.py
+++ b/lib/galaxy/objectstore/s3_boto3.py
@@ -2,15 +2,14 @@
import logging
import os
+from collections.abc import Callable
from typing import (
Any,
- Callable,
- Dict,
+ Literal,
TYPE_CHECKING,
)
from typing_extensions import (
- Literal,
NotRequired,
TypedDict,
)
@@ -167,7 +166,7 @@ class S3ObjectStore(CachingConcreteObjectStore):
transfer_dict = config_dict.get("transfer") or {}
typed_transfer_dict = {}
for prefix in ["", "upload_", "download_"]:
- options: Dict[str, Callable[[Any], Any]] = {
+ options: dict[str, Callable[[Any], Any]] = {
"multipart_threshold": int,
"max_concurrency": int,
"multipart_chunksize": int,
diff --git a/lib/galaxy/objectstore/templates/manager.py b/lib/galaxy/objectstore/templates/manager.py
index bb5be1c722c..7d36d5f92fb 100644
--- a/lib/galaxy/objectstore/templates/manager.py
+++ b/lib/galaxy/objectstore/templates/manager.py
@@ -1,8 +1,4 @@
import os
-from typing import (
- List,
- Optional,
-)
from typing_extensions import Protocol
from yaml import safe_load
@@ -26,8 +22,8 @@ from .models import (
class AppConfigProtocol(Protocol):
- object_store_templates: Optional[List[RawTemplateConfig]]
- object_store_templates_config_file: Optional[str]
+ object_store_templates: list[RawTemplateConfig] | None
+ object_store_templates_config_file: str | None
SECRETS_NEED_VAULT_MESSAGE = "The object store templates configuration can not be used - a Galaxy vault must be configured for templates that use secrets - please set the vault_config_file configuration option to point at a valid vault configuration."
@@ -86,6 +82,6 @@ class ConfiguredObjectStoreTemplates:
validate_secrets_and_variables(instance, template)
-def raw_config_to_catalog(raw_config: List[RawTemplateConfig]) -> ObjectStoreTemplateCatalog:
+def raw_config_to_catalog(raw_config: list[RawTemplateConfig]) -> ObjectStoreTemplateCatalog:
effective_root = apply_syntactic_sugar(raw_config)
return ObjectStoreTemplateCatalog.model_validate(effective_root)
diff --git a/lib/galaxy/objectstore/templates/models.py b/lib/galaxy/objectstore/templates/models.py
index b6aefcda1e2..eaef3d27229 100644
--- a/lib/galaxy/objectstore/templates/models.py
+++ b/lib/galaxy/objectstore/templates/models.py
@@ -1,21 +1,14 @@
from typing import (
+ Annotated,
Any,
- Dict,
- List,
- Optional,
- Type,
- Union,
+ Literal,
+ TypeAlias,
)
from pydantic import (
Field,
RootModel,
)
-from typing_extensions import (
- Annotated,
- Literal,
- TypeAlias,
-)
from galaxy.objectstore.badges import (
BadgeDict,
@@ -45,8 +38,8 @@ ObjectStoreTemplateType = Literal["aws_s3", "azure_blob", "boto3", "disk", "gene
class S3AuthTemplate(StrictModel):
- access_key: Union[str, TemplateExpansion]
- secret_key: Union[str, TemplateExpansion]
+ access_key: str | TemplateExpansion
+ secret_key: str | TemplateExpansion
class S3Auth(StrictModel):
@@ -55,16 +48,16 @@ class S3Auth(StrictModel):
class S3BucketTemplate(StrictModel):
- name: Union[str, TemplateExpansion]
- use_reduced_redundancy: Optional[Union[bool, TemplateExpansion]] = None
+ name: str | TemplateExpansion
+ use_reduced_redundancy: bool | TemplateExpansion | None = None
class S3Bucket(StrictModel):
name: str
- use_reduced_redundancy: Optional[bool] = None
+ use_reduced_redundancy: bool | None = None
-BadgeList = Optional[List[StoredBadgeDict]]
+BadgeList = list[StoredBadgeDict] | None
class AwsS3ObjectStoreTemplateConfiguration(StrictModel):
@@ -72,8 +65,8 @@ class AwsS3ObjectStoreTemplateConfiguration(StrictModel):
auth: S3AuthTemplate
bucket: S3BucketTemplate
badges: BadgeList = None
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ template_start: str | None = None
+ template_end: str | None = None
class AwsS3ObjectStoreConfiguration(StrictModel):
@@ -84,8 +77,8 @@ class AwsS3ObjectStoreConfiguration(StrictModel):
class AzureAuthTemplate(StrictModel):
- account_name: Union[str, TemplateExpansion]
- account_key: Union[str, TemplateExpansion]
+ account_name: str | TemplateExpansion
+ account_key: str | TemplateExpansion
class AzureAuth(StrictModel):
@@ -94,7 +87,7 @@ class AzureAuth(StrictModel):
class AzureContainerTemplate(StrictModel):
- name: Union[str, TemplateExpansion]
+ name: str | TemplateExpansion
class AzureContainer(StrictModel):
@@ -102,86 +95,86 @@ class AzureContainer(StrictModel):
class AzureTransferTemplate(StrictModel):
- max_concurrency: Optional[Union[int, TemplateExpansion]] = None
- download_max_concurrency: Optional[Union[int, TemplateExpansion]] = None
- upload_max_concurrency: Optional[Union[int, TemplateExpansion]] = None
- max_single_put_size: Optional[Union[int, TemplateExpansion]] = None
- max_single_get_size: Optional[Union[int, TemplateExpansion]] = None
- max_block_size: Optional[Union[int, TemplateExpansion]] = None
+ max_concurrency: int | TemplateExpansion | None = None
+ download_max_concurrency: int | TemplateExpansion | None = None
+ upload_max_concurrency: int | TemplateExpansion | None = None
+ max_single_put_size: int | TemplateExpansion | None = None
+ max_single_get_size: int | TemplateExpansion | None = None
+ max_block_size: int | TemplateExpansion | None = None
class AzureObjectStoreTemplateConfiguration(StrictModel):
type: Literal["azure_blob"]
auth: AzureAuthTemplate
container: AzureContainerTemplate
- transfer: Optional[AzureTransferTemplate] = None
+ transfer: AzureTransferTemplate | None = None
badges: BadgeList = None
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ template_start: str | None = None
+ template_end: str | None = None
class AzureTransfer(StrictModel):
- max_concurrency: Optional[int] = None
- download_max_concurrency: Optional[int] = None
- upload_max_concurrency: Optional[int] = None
- max_single_put_size: Optional[int] = None
- max_single_get_size: Optional[int] = None
- max_block_size: Optional[int] = None
+ max_concurrency: int | None = None
+ download_max_concurrency: int | None = None
+ upload_max_concurrency: int | None = None
+ max_single_put_size: int | None = None
+ max_single_get_size: int | None = None
+ max_block_size: int | None = None
class AzureObjectStoreConfiguration(StrictModel):
type: Literal["azure_blob"]
auth: AzureAuth
container: AzureContainer
- transfer: Optional[AzureTransfer] = None
+ transfer: AzureTransfer | None = None
badges: BadgeList = None
class Boto3BucketTemplate(StrictModel):
- name: Union[str, TemplateExpansion]
+ name: str | TemplateExpansion
class Boto3ConnectionTemplate(StrictModel):
- endpoint_url: Union[str, TemplateExpansion]
- region: Optional[Union[str, TemplateExpansion]] = None
+ endpoint_url: str | TemplateExpansion
+ region: str | TemplateExpansion | None = None
class Boto3TransferTemplate(StrictModel):
- use_threads: Optional[Union[bool, TemplateExpansion]] = None
- multipart_threshold: Optional[Union[int, TemplateExpansion]] = None
- max_concurrency: Optional[Union[int, TemplateExpansion]] = None
- multipart_chunksize: Optional[Union[int, TemplateExpansion]] = None
- num_download_attempts: Optional[Union[int, TemplateExpansion]] = None
- max_io_queue: Optional[Union[int, TemplateExpansion]] = None
- io_chunksize: Optional[Union[int, TemplateExpansion]] = None
- max_bandwidth: Optional[Union[int, TemplateExpansion]] = None
- download_use_threads: Optional[Union[bool, TemplateExpansion]] = None
- download_multipart_threshold: Optional[Union[int, TemplateExpansion]] = None
- download_max_concurrency: Optional[Union[int, TemplateExpansion]] = None
- download_multipart_chunksize: Optional[Union[int, TemplateExpansion]] = None
- download_num_download_attempts: Optional[Union[int, TemplateExpansion]] = None
- download_max_io_queue: Optional[Union[int, TemplateExpansion]] = None
- download_io_chunksize: Optional[Union[int, TemplateExpansion]] = None
- download_max_bandwidth: Optional[Union[int, TemplateExpansion]] = None
- upload_use_threads: Optional[Union[bool, TemplateExpansion]] = None
- upload_multipart_threshold: Optional[Union[int, TemplateExpansion]] = None
- upload_max_concurrency: Optional[Union[int, TemplateExpansion]] = None
- upload_multipart_chunksize: Optional[Union[int, TemplateExpansion]] = None
- upload_num_download_attempts: Optional[Union[int, TemplateExpansion]] = None
- upload_max_io_queue: Optional[Union[int, TemplateExpansion]] = None
- upload_io_chunksize: Optional[Union[int, TemplateExpansion]] = None
- upload_max_bandwidth: Optional[Union[int, TemplateExpansion]] = None
+ use_threads: bool | TemplateExpansion | None = None
+ multipart_threshold: int | TemplateExpansion | None = None
+ max_concurrency: int | TemplateExpansion | None = None
+ multipart_chunksize: int | TemplateExpansion | None = None
+ num_download_attempts: int | TemplateExpansion | None = None
+ max_io_queue: int | TemplateExpansion | None = None
+ io_chunksize: int | TemplateExpansion | None = None
+ max_bandwidth: int | TemplateExpansion | None = None
+ download_use_threads: bool | TemplateExpansion | None = None
+ download_multipart_threshold: int | TemplateExpansion | None = None
+ download_max_concurrency: int | TemplateExpansion | None = None
+ download_multipart_chunksize: int | TemplateExpansion | None = None
+ download_num_download_attempts: int | TemplateExpansion | None = None
+ download_max_io_queue: int | TemplateExpansion | None = None
+ download_io_chunksize: int | TemplateExpansion | None = None
+ download_max_bandwidth: int | TemplateExpansion | None = None
+ upload_use_threads: bool | TemplateExpansion | None = None
+ upload_multipart_threshold: int | TemplateExpansion | None = None
+ upload_max_concurrency: int | TemplateExpansion | None = None
+ upload_multipart_chunksize: int | TemplateExpansion | None = None
+ upload_num_download_attempts: int | TemplateExpansion | None = None
+ upload_max_io_queue: int | TemplateExpansion | None = None
+ upload_io_chunksize: int | TemplateExpansion | None = None
+ upload_max_bandwidth: int | TemplateExpansion | None = None
class Boto3ObjectStoreTemplateConfiguration(StrictModel):
type: Literal["boto3"]
auth: S3AuthTemplate
bucket: Boto3BucketTemplate
- connection: Optional[Boto3ConnectionTemplate] = None
- transfer: Optional[Boto3TransferTemplate] = None
+ connection: Boto3ConnectionTemplate | None = None
+ transfer: Boto3TransferTemplate | None = None
badges: BadgeList = None
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ template_start: str | None = None
+ template_end: str | None = None
class Boto3Bucket(StrictModel):
@@ -190,51 +183,51 @@ class Boto3Bucket(StrictModel):
class Boto3Connection(StrictModel):
endpoint_url: str
- region: Optional[str] = None
+ region: str | None = None
class Boto3Transfer(StrictModel):
- use_threads: Optional[bool] = None
- multipart_threshold: Optional[int] = None
- max_concurrency: Optional[int] = None
- multipart_chunksize: Optional[int] = None
- num_download_attempts: Optional[int] = None
- max_io_queue: Optional[int] = None
- io_chunksize: Optional[int] = None
- max_bandwidth: Optional[int] = None
- download_use_threads: Optional[bool] = None
- download_multipart_threshold: Optional[int] = None
- download_max_concurrency: Optional[int] = None
- download_multipart_chunksize: Optional[int] = None
- download_num_download_attempts: Optional[int] = None
- download_max_io_queue: Optional[int] = None
- download_io_chunksize: Optional[int] = None
- download_max_bandwidth: Optional[int] = None
- upload_use_threads: Optional[bool] = None
- upload_multipart_threshold: Optional[int] = None
- upload_max_concurrency: Optional[int] = None
- upload_multipart_chunksize: Optional[int] = None
- upload_num_download_attempts: Optional[int] = None
- upload_max_io_queue: Optional[int] = None
- upload_io_chunksize: Optional[int] = None
- upload_max_bandwidth: Optional[int] = None
+ use_threads: bool | None = None
+ multipart_threshold: int | None = None
+ max_concurrency: int | None = None
+ multipart_chunksize: int | None = None
+ num_download_attempts: int | None = None
+ max_io_queue: int | None = None
+ io_chunksize: int | None = None
+ max_bandwidth: int | None = None
+ download_use_threads: bool | None = None
+ download_multipart_threshold: int | None = None
+ download_max_concurrency: int | None = None
+ download_multipart_chunksize: int | None = None
+ download_num_download_attempts: int | None = None
+ download_max_io_queue: int | None = None
+ download_io_chunksize: int | None = None
+ download_max_bandwidth: int | None = None
+ upload_use_threads: bool | None = None
+ upload_multipart_threshold: int | None = None
+ upload_max_concurrency: int | None = None
+ upload_multipart_chunksize: int | None = None
+ upload_num_download_attempts: int | None = None
+ upload_max_io_queue: int | None = None
+ upload_io_chunksize: int | None = None
+ upload_max_bandwidth: int | None = None
class Boto3ObjectStoreConfiguration(StrictModel):
type: Literal["boto3"]
auth: S3Auth
bucket: Boto3Bucket
- connection: Optional[Boto3Connection] = None
- transfer: Optional[Boto3Transfer] = None
+ connection: Boto3Connection | None = None
+ transfer: Boto3Transfer | None = None
badges: BadgeList = None
class DiskObjectStoreTemplateConfiguration(StrictModel):
type: Literal["disk"]
- files_dir: Union[str, TemplateExpansion]
+ files_dir: str | TemplateExpansion
badges: BadgeList = None
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ template_start: str | None = None
+ template_end: str | None = None
class DiskObjectStoreConfiguration(StrictModel):
@@ -244,10 +237,10 @@ class DiskObjectStoreConfiguration(StrictModel):
class S3ConnectionTemplate(StrictModel):
- host: Union[str, TemplateExpansion]
- port: Union[int, TemplateExpansion]
- is_secure: Optional[Union[bool, TemplateExpansion]] = True
- conn_path: Optional[Union[str, TemplateExpansion]] = ""
+ host: str | TemplateExpansion
+ port: int | TemplateExpansion
+ is_secure: bool | TemplateExpansion | None = True
+ conn_path: str | TemplateExpansion | None = ""
class S3Connection(StrictModel):
@@ -263,8 +256,8 @@ class GenericS3ObjectStoreTemplateConfiguration(StrictModel):
bucket: S3BucketTemplate
connection: S3ConnectionTemplate
badges: BadgeList = None
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ template_start: str | None = None
+ template_end: str | None = None
class GenericS3ObjectStoreConfiguration(StrictModel):
@@ -276,7 +269,7 @@ class GenericS3ObjectStoreConfiguration(StrictModel):
class OnedataAuthTemplate(StrictModel):
- access_token: Union[str, TemplateExpansion]
+ access_token: str | TemplateExpansion
class OnedataAuth(StrictModel):
@@ -284,8 +277,8 @@ class OnedataAuth(StrictModel):
class OnedataConnectionTemplate(StrictModel):
- onezone_domain: Union[str, TemplateExpansion]
- disable_tls_certificate_validation: Union[bool, TemplateExpansion] = False
+ onezone_domain: str | TemplateExpansion
+ disable_tls_certificate_validation: bool | TemplateExpansion = False
class OnedataConnection(StrictModel):
@@ -294,8 +287,8 @@ class OnedataConnection(StrictModel):
class OnedataSpaceTemplate(StrictModel):
- name: Union[str, TemplateExpansion]
- galaxy_root_dir: Optional[Union[str, TemplateExpansion]] = ""
+ name: str | TemplateExpansion
+ galaxy_root_dir: str | TemplateExpansion | None = ""
class OnedataSpace(StrictModel):
@@ -309,8 +302,8 @@ class OnedataObjectStoreTemplateConfiguration(StrictModel):
connection: OnedataConnectionTemplate
space: OnedataSpaceTemplate
badges: BadgeList = None
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ template_start: str | None = None
+ template_end: str | None = None
class OnedataObjectStoreConfiguration(StrictModel):
@@ -325,27 +318,27 @@ class RucioObjectStoreTemplateConfiguration(StrictModel):
type: Literal["rucio"]
scope: str
upload_rse_name: str
- upload_scheme: Optional[Any] = None
- download_schemes: Optional[Any] = None
+ upload_scheme: Any | None = None
+ download_schemes: Any | None = None
auth_host: str
host: str
auth_type: str
- account: Union[str, TemplateExpansion]
- username: Union[str, TemplateExpansion]
- password: Union[str, TemplateExpansion]
+ account: str | TemplateExpansion
+ username: str | TemplateExpansion
+ password: str | TemplateExpansion
badges: BadgeList = None
- register_only: Optional[bool] = False
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ register_only: bool | None = False
+ template_start: str | None = None
+ template_end: str | None = None
class RucioObjectStoreConfiguration(StrictModel):
type: Literal["rucio"]
scope: str
upload_rse_name: str
- upload_scheme: Optional[Any] = None
- download_schemes: Optional[Any] = None
- register_only: Optional[bool] = False
+ upload_scheme: Any | None = None
+ download_schemes: Any | None = None
+ register_only: bool | None = False
auth_host: str
host: str
auth_type: str
@@ -359,8 +352,8 @@ class RucioObjectStoreConfiguration(StrictModel):
class IrodsAuthTemplate(StrictModel):
- username: Union[str, TemplateExpansion]
- password: Union[str, TemplateExpansion]
+ username: str | TemplateExpansion
+ password: str | TemplateExpansion
class IrodsAuth(StrictModel):
@@ -369,31 +362,31 @@ class IrodsAuth(StrictModel):
class IrodsConnectionTemplate(StrictModel):
- host: Union[str, TemplateExpansion]
- port: Union[int, TemplateExpansion]
- timeout: Optional[Union[int, TemplateExpansion]]
- refresh_time: Optional[Union[int, TemplateExpansion]]
- connection_pool_monitor_interval: Optional[Union[int, TemplateExpansion]]
+ host: str | TemplateExpansion
+ port: int | TemplateExpansion
+ timeout: int | TemplateExpansion | None
+ refresh_time: int | TemplateExpansion | None
+ connection_pool_monitor_interval: int | TemplateExpansion | None
class IrodsConnection(StrictModel):
host: str
- port: Optional[int]
- timeout: Optional[int] = None
- refresh_time: Optional[int] = None
- connection_pool_monitor_interval: Optional[int] = None
+ port: int | None
+ timeout: int | None = None
+ refresh_time: int | None = None
+ connection_pool_monitor_interval: int | None = None
class IrodsPathTemplate(StrictModel):
- path: Optional[Union[str, TemplateExpansion]] = ""
+ path: str | TemplateExpansion | None = ""
class IrodsPath(StrictModel):
- path: Optional[str] = ""
+ path: str | None = ""
class IrodsResourceTemplate(StrictModel):
- name: Union[str, TemplateExpansion]
+ name: str | TemplateExpansion
class IrodsResource(StrictModel):
@@ -401,7 +394,7 @@ class IrodsResource(StrictModel):
class IrodsZoneTemplate(StrictModel):
- name: Union[str, TemplateExpansion]
+ name: str | TemplateExpansion
class IrodsZone(StrictModel):
@@ -409,25 +402,25 @@ class IrodsZone(StrictModel):
class IrodsSslTemplate(StrictModel):
- client_server_negotiation: Optional[Union[str, TemplateExpansion]] = ""
- client_server_policy: Optional[Union[str, TemplateExpansion]] = ""
- encryption_algorithm: Optional[Union[str, TemplateExpansion]] = ""
- encryption_key_size: Optional[Union[int, TemplateExpansion]] = None
- encryption_num_hash_rounds: Optional[Union[int, TemplateExpansion]] = None
- encryption_salt_size: Optional[Union[int, TemplateExpansion]] = None
- ssl_verify_server: Optional[Union[str, TemplateExpansion]] = ""
- ssl_ca_certificate_file: Optional[Union[str, TemplateExpansion]] = ""
+ client_server_negotiation: str | TemplateExpansion | None = ""
+ client_server_policy: str | TemplateExpansion | None = ""
+ encryption_algorithm: str | TemplateExpansion | None = ""
+ encryption_key_size: int | TemplateExpansion | None = None
+ encryption_num_hash_rounds: int | TemplateExpansion | None = None
+ encryption_salt_size: int | TemplateExpansion | None = None
+ ssl_verify_server: str | TemplateExpansion | None = ""
+ ssl_ca_certificate_file: str | TemplateExpansion | None = ""
class IrodsSsl(StrictModel):
- client_server_negotiation: Optional[str] = ""
- client_server_policy: Optional[str] = ""
- encryption_algorithm: Optional[str] = ""
- encryption_key_size: Optional[int] = None
- encryption_num_hash_rounds: Optional[int] = None
- encryption_salt_size: Optional[int] = None
- ssl_verify_server: Optional[str] = ""
- ssl_ca_certificate_file: Optional[str] = ""
+ client_server_negotiation: str | None = ""
+ client_server_policy: str | None = ""
+ encryption_algorithm: str | None = ""
+ encryption_key_size: int | None = None
+ encryption_num_hash_rounds: int | None = None
+ encryption_salt_size: int | None = None
+ ssl_verify_server: str | None = ""
+ ssl_ca_certificate_file: str | None = ""
class IrodsObjectStoreTemplateConfiguration(StrictModel):
@@ -436,11 +429,11 @@ class IrodsObjectStoreTemplateConfiguration(StrictModel):
connection: IrodsConnectionTemplate
zone: IrodsZoneTemplate
resource: IrodsResourceTemplate
- ssl: Optional[IrodsSslTemplate] = None
- logical: Optional[IrodsPathTemplate] = None
+ ssl: IrodsSslTemplate | None = None
+ logical: IrodsPathTemplate | None = None
badges: BadgeList = None
- template_start: Optional[str] = None
- template_end: Optional[str] = None
+ template_start: str | None = None
+ template_end: str | None = None
class IrodsObjectStoreConfiguration(StrictModel):
@@ -449,36 +442,32 @@ class IrodsObjectStoreConfiguration(StrictModel):
connection: IrodsConnection
zone: IrodsZone
resource: IrodsResource
- ssl: Optional[IrodsSsl] = None
- logical: Optional[IrodsPath] = None
+ ssl: IrodsSsl | None = None
+ logical: IrodsPath | None = None
badges: BadgeList = None
ObjectStoreTemplateConfiguration = Annotated[
- Union[
- AwsS3ObjectStoreTemplateConfiguration,
- Boto3ObjectStoreTemplateConfiguration,
- GenericS3ObjectStoreTemplateConfiguration,
- DiskObjectStoreTemplateConfiguration,
- AzureObjectStoreTemplateConfiguration,
- OnedataObjectStoreTemplateConfiguration,
- RucioObjectStoreTemplateConfiguration,
- IrodsObjectStoreTemplateConfiguration,
- ],
+ AwsS3ObjectStoreTemplateConfiguration
+ | Boto3ObjectStoreTemplateConfiguration
+ | GenericS3ObjectStoreTemplateConfiguration
+ | DiskObjectStoreTemplateConfiguration
+ | AzureObjectStoreTemplateConfiguration
+ | OnedataObjectStoreTemplateConfiguration
+ | RucioObjectStoreTemplateConfiguration
+ | IrodsObjectStoreTemplateConfiguration,
Field(discriminator="type"),
]
ObjectStoreConfiguration = Annotated[
- Union[
- AwsS3ObjectStoreConfiguration,
- Boto3ObjectStoreConfiguration,
- DiskObjectStoreConfiguration,
- AzureObjectStoreConfiguration,
- GenericS3ObjectStoreConfiguration,
- OnedataObjectStoreConfiguration,
- RucioObjectStoreConfiguration,
- IrodsObjectStoreConfiguration,
- ],
+ AwsS3ObjectStoreConfiguration
+ | Boto3ObjectStoreConfiguration
+ | DiskObjectStoreConfiguration
+ | AzureObjectStoreConfiguration
+ | GenericS3ObjectStoreConfiguration
+ | OnedataObjectStoreConfiguration
+ | RucioObjectStoreConfiguration
+ | IrodsObjectStoreConfiguration,
Field(discriminator="type"),
]
@@ -494,8 +483,8 @@ class ObjectStoreTemplateBase(StrictModel):
"""
id: str
- name: Optional[str]
- description: Optional[MarkdownContent]
+ name: str | None
+ description: MarkdownContent | None
# The UI should just show the most recent version but allow
# admins to define newer versions with new parameterizations
# and keep old versions in template catalog for backward compatibility
@@ -505,38 +494,38 @@ class ObjectStoreTemplateBase(StrictModel):
# template by hiding but keep it in the catalog for backward
# compatibility for users with existing stores of that template.
hidden: bool = False
- variables: Optional[List[TemplateVariable]] = None
- secrets: Optional[List[TemplateSecret]] = None
+ variables: list[TemplateVariable] | None = None
+ secrets: list[TemplateSecret] | None = None
class ObjectStoreTemplateSummary(ObjectStoreTemplateBase):
- badges: List[BadgeDict]
+ badges: list[BadgeDict]
type: ObjectStoreTemplateType
class ObjectStoreTemplate(ObjectStoreTemplateBase):
configuration: ObjectStoreTemplateConfiguration
- environment: Optional[List[TemplateEnvironmentEntry]] = None
+ environment: list[TemplateEnvironmentEntry] | None = None
@property
def type(self):
return self.configuration.type
-ObjectStoreTemplateCatalog = RootModel[List[ObjectStoreTemplate]]
+ObjectStoreTemplateCatalog = RootModel[list[ObjectStoreTemplate]]
class ObjectStoreTemplateSummaries(RootModel):
- root: List[ObjectStoreTemplateSummary]
+ root: list[ObjectStoreTemplateSummary]
def template_to_configuration(
template: ObjectStoreTemplate,
- variables: Dict[str, ObjectStoreTemplateVariableValueType],
+ variables: dict[str, ObjectStoreTemplateVariableValueType],
secrets: SecretsDict,
user_details: UserDetailsDict,
environment: EnvironmentDict,
- implicit: Optional[ImplicitConfigurationParameters] = None,
+ implicit: ImplicitConfigurationParameters | None = None,
) -> ObjectStoreConfiguration:
configuration_template = template.configuration
populate_default_variables(template.variables, variables)
@@ -545,7 +534,7 @@ def template_to_configuration(
return to_configuration_object(raw_config)
-TypesToConfigurationClasses: Dict[ObjectStoreTemplateType, Type[ObjectStoreConfiguration]] = {
+TypesToConfigurationClasses: dict[ObjectStoreTemplateType, type[ObjectStoreConfiguration]] = {
"aws_s3": AwsS3ObjectStoreConfiguration,
"boto3": Boto3ObjectStoreConfiguration,
"generic_s3": GenericS3ObjectStoreConfiguration,
@@ -557,7 +546,7 @@ TypesToConfigurationClasses: Dict[ObjectStoreTemplateType, Type[ObjectStoreConfi
}
-def to_configuration_object(configuration_dict: Dict[str, Any]) -> ObjectStoreConfiguration:
+def to_configuration_object(configuration_dict: dict[str, Any]) -> ObjectStoreConfiguration:
if "type" not in configuration_dict:
raise KeyError("Configuration objects require an object store 'type' key, none found.")
object_store_type = configuration_dict["type"]
diff --git a/lib/galaxy/objectstore/unittest_utils/__init__.py b/lib/galaxy/objectstore/unittest_utils/__init__.py
index 9181d38af61..f014079d80b 100644
--- a/lib/galaxy/objectstore/unittest_utils/__init__.py
+++ b/lib/galaxy/objectstore/unittest_utils/__init__.py
@@ -6,7 +6,6 @@ from io import StringIO
from shutil import rmtree
from string import Template
from tempfile import mkdtemp
-from typing import Optional
import yaml
@@ -39,7 +38,7 @@ class Config:
config_str=DISK_TEST_CONFIG,
clazz=None,
store_by="id",
- user_object_store_resolver: Optional[objectstore.UserObjectStoreResolver] = None,
+ user_object_store_resolver: objectstore.UserObjectStoreResolver | None = None,
template_vars=None,
inject_galaxy_test_env=False,
):
diff --git a/lib/galaxy/queue_worker/__init__.py b/lib/galaxy/queue_worker/__init__.py
index 425dec9dce3..7358a37c6c4 100644
--- a/lib/galaxy/queue_worker/__init__.py
+++ b/lib/galaxy/queue_worker/__init__.py
@@ -15,7 +15,6 @@ from inspect import ismodule
from typing import (
Any,
cast,
- Optional,
TYPE_CHECKING,
TypedDict,
)
@@ -56,14 +55,14 @@ class NotifyUsersPayload(TypedDict, total=False):
user_ids: list[int]
payload: str
- event_id: Optional[str]
+ event_id: str | None
class NotifyBroadcastPayload(TypedDict, total=False):
"""Wire contract for the ``notify_broadcast`` control-task kwargs."""
payload: str
- event_id: Optional[str]
+ event_id: str | None
class HistoryUpdatePayload(TypedDict, total=False):
@@ -78,14 +77,14 @@ class HistoryUpdatePayload(TypedDict, total=False):
user_updates: dict[str, list[int]]
session_updates: dict[str, list[int]]
- event_id: Optional[str]
+ event_id: str | None
class EntryPointUpdatePayload(TypedDict, total=False):
"""Wire contract for the ``entry_point_update`` control-task kwargs."""
user_id: int
- event_id: Optional[str]
+ event_id: str | None
class HistoryViewerSubscriptionPayload(TypedDict, total=False):
@@ -106,7 +105,7 @@ def send_local_control_task(
app: "StructuredApp",
task: str,
get_response: bool = False,
- kwargs: Optional[dict] = None,
+ kwargs: dict | None = None,
) -> Any:
"""
This sends a message to the process-local control worker, which is useful
@@ -127,9 +126,9 @@ def send_control_task(
noop_self: bool = False,
get_response: bool = False,
routing_key: str = "control.*",
- kwargs: Optional[dict] = None,
- expiration: Optional[int] = None,
- declare_queues: Optional[list[Queue]] = None,
+ kwargs: dict | None = None,
+ expiration: int | None = None,
+ declare_queues: list[Queue] | None = None,
) -> Any:
"""
This sends a control task out to all processes, useful for things like
@@ -196,8 +195,8 @@ class ControlTask:
local: bool = False,
get_response: bool = False,
timeout: int = 10,
- expiration: Optional[int] = None,
- declare_queues: Optional[list[Queue]] = None,
+ expiration: int | None = None,
+ declare_queues: list[Queue] | None = None,
):
if local:
declare_queues = self.control_queues
diff --git a/lib/galaxy/queues/__init__.py b/lib/galaxy/queues/__init__.py
index 21bb1df6d01..c66fd682dc0 100644
--- a/lib/galaxy/queues/__init__.py
+++ b/lib/galaxy/queues/__init__.py
@@ -8,7 +8,6 @@ import datetime
import logging
import socket
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -79,7 +78,7 @@ def control_queues_from_config(config):
return exchange_queue, non_exchange_queue
-def connection_from_config(config) -> Optional[Connection]:
+def connection_from_config(config) -> Connection | None:
if config.amqp_internal_connection:
return Connection(config.amqp_internal_connection)
else:
diff --git a/lib/galaxy/quota/__init__.py b/lib/galaxy/quota/__init__.py
index 083ac524d94..2430539a152 100644
--- a/lib/galaxy/quota/__init__.py
+++ b/lib/galaxy/quota/__init__.py
@@ -1,7 +1,6 @@
"""Galaxy Quotas"""
import logging
-from typing import Optional
from sqlalchemy import select
from sqlalchemy.sql import text
@@ -26,7 +25,7 @@ class QuotaAgent: # metaclass=abc.ABCMeta
the quota in other apps (LDAP maybe?) or via configuration files.
"""
- def relabel_quota_for_dataset(self, dataset, from_label: Optional[str], to_label: Optional[str]):
+ def relabel_quota_for_dataset(self, dataset, from_label: str | None, to_label: str | None):
"""Update the quota source label for dataset and adjust relevant quotas.
Subtract quota for labels from users using old label and quota for new label
@@ -34,10 +33,10 @@ class QuotaAgent: # metaclass=abc.ABCMeta
"""
# TODO: make abstractmethod after they work better with mypy
- def get_quota(self, user, quota_source_label=None) -> Optional[int]:
+ def get_quota(self, user, quota_source_label=None) -> int | None:
"""Return quota in bytes or None if no quota is set."""
- def get_quota_nice_size(self, user, quota_source_label=None) -> Optional[str]:
+ def get_quota_nice_size(self, user, quota_source_label=None) -> str | None:
"""Return quota as a human-readable string or 'unlimited' if no quota is set."""
quota_bytes = self.get_quota(user, quota_source_label=quota_source_label)
if quota_bytes is not None:
@@ -49,10 +48,10 @@ class QuotaAgent: # metaclass=abc.ABCMeta
# TODO: make abstractmethod after they work better with mypy
def get_percent(
self, trans=None, user=False, history=False, usage=False, quota=False, quota_source_label=None
- ) -> Optional[int]:
+ ) -> int | None:
"""Return the percentage of any storage quota applicable to the user/transaction."""
- def get_usage(self, trans=None, user=False, history=False, quota_source_label=None) -> Optional[float]:
+ def get_usage(self, trans=None, user=False, history=False, quota_source_label=None) -> float | None:
if trans:
user = trans.user
history = trans.history
@@ -81,10 +80,10 @@ class NoQuotaAgent(QuotaAgent):
def __init__(self):
pass
- def get_quota(self, user, quota_source_label=None) -> Optional[int]:
+ def get_quota(self, user, quota_source_label=None) -> int | None:
return None
- def relabel_quota_for_dataset(self, dataset, from_label: Optional[str], to_label: Optional[str]):
+ def relabel_quota_for_dataset(self, dataset, from_label: str | None, to_label: str | None):
return None
@property
@@ -93,7 +92,7 @@ class NoQuotaAgent(QuotaAgent):
def get_percent(
self, trans=None, user=False, history=False, usage=False, quota=False, quota_source_label=None
- ) -> Optional[int]:
+ ) -> int | None:
return None
def is_over_quota(self, quota_source_map, job):
@@ -107,7 +106,7 @@ class DatabaseQuotaAgent(QuotaAgent):
self.model = model
self.sa_session = model.context
- def get_quota(self, user, quota_source_label=None) -> Optional[int]:
+ def get_quota(self, user, quota_source_label=None) -> int | None:
"""
Calculated like so:
@@ -175,7 +174,7 @@ FROM (
else:
return None
- def relabel_quota_for_dataset(self, dataset, from_label: Optional[str], to_label: Optional[str]):
+ def relabel_quota_for_dataset(self, dataset, from_label: str | None, to_label: str | None):
adjust = dataset.get_total_size()
with_quota_affected_users = """WITH quota_affected_users AS
(
@@ -318,7 +317,7 @@ WHERE default_quota_association.type = :default_type
def get_percent(
self, trans=None, user=False, history=False, usage=False, quota=False, quota_source_label=None
- ) -> Optional[int]:
+ ) -> int | None:
"""
Return the percentage of any storage quota applicable to the user/transaction.
"""
diff --git a/lib/galaxy/quota/_schema.py b/lib/galaxy/quota/_schema.py
index e0fee00f1d0..a189039d96b 100644
--- a/lib/galaxy/quota/_schema.py
+++ b/lib/galaxy/quota/_schema.py
@@ -1,7 +1,6 @@
from enum import Enum
from typing import (
Literal,
- Optional,
)
from pydantic import (
@@ -112,7 +111,7 @@ class QuotaBase(Model, WithModelClass):
description="The `encoded identifier` of the quota.",
)
name: str = QuotaNameField
- quota_source_label: Optional[str] = Field(
+ quota_source_label: str | None = Field(
None,
title="Quota Source Label",
description="Quota source label",
@@ -194,17 +193,17 @@ class CreateQuotaParams(Model):
" equivalent to ``no``."
),
)
- quota_source_label: Optional[str] = Field(
+ quota_source_label: str | None = Field(
default=None,
title="Quota Source Label",
description="If set, quota source label to apply this quota operation to. Otherwise, the default quota is used.",
)
- in_users: Optional[list[str]] = Field(
+ in_users: list[str] | None = Field(
default=[],
title="Users",
description="A list of user IDs or user emails to associate with this quota.",
)
- in_groups: Optional[list[str]] = Field(
+ in_groups: list[str] | None = Field(
default=[],
title="Groups",
description="A list of group IDs or names to associate with this quota.",
@@ -212,17 +211,17 @@ class CreateQuotaParams(Model):
class UpdateQuotaParams(Model):
- name: Optional[str] = Field(
+ name: str | None = Field(
default=None,
title="Name",
description="The new name of the quota. This must be unique within a Galaxy instance.",
)
- description: Optional[str] = Field(
+ description: str | None = Field(
None,
title="Description",
description="Detailed text description for this Quota.",
)
- amount: Optional[str] = Field(
+ amount: str | None = Field(
None,
title="Amount",
description="Quota size (E.g. ``10000MB``, ``99 gb``, ``0.2T``, ``unlimited``)",
@@ -235,7 +234,7 @@ class UpdateQuotaParams(Model):
" you must also provide the ``amount``, otherwise it will not take effect."
),
)
- default: Optional[DefaultQuotaValues] = Field(
+ default: DefaultQuotaValues | None = Field(
default=None,
title="Default",
description=(
@@ -246,12 +245,12 @@ class UpdateQuotaParams(Model):
" passing this parameter is equivalent to passing ``no``."
),
)
- in_users: Optional[list[str]] = Field(
+ in_users: list[str] | None = Field(
default=None,
title="Users",
description="A list of user IDs or user emails to associate with this quota.",
)
- in_groups: Optional[list[str]] = Field(
+ in_groups: list[str] | None = Field(
default=None,
title="Groups",
description="A list of group IDs or names to associate with this quota.",
diff --git a/lib/galaxy/schema/__init__.py b/lib/galaxy/schema/__init__.py
index 7a1c2f7a20d..7e862c72b7d 100644
--- a/lib/galaxy/schema/__init__.py
+++ b/lib/galaxy/schema/__init__.py
@@ -1,9 +1,5 @@
from datetime import datetime
from enum import Enum
-from typing import (
- Optional,
- Union,
-)
from pydantic import (
BaseModel,
@@ -13,8 +9,8 @@ from pydantic import (
class BootstrapAdminUser(BaseModel):
id: int = 0
- email: Optional[str] = None
- username: Optional[str] = None
+ email: str | None = None
+ username: str | None = None
preferences: dict[str, str] = {}
bootstrap_admin_user: bool = True
@@ -28,13 +24,13 @@ class ValueFilterQueryParams(BaseModel):
Multiple `q/qv` queries can be concatenated.
"""
- q: Optional[Union[list[str], str]] = Field(
+ q: list[str] | str | None = Field(
default=None,
title="Filter Query",
description="Generally a property name to filter by followed by an (often optional) hyphen and operator string.",
examples=["create_time-gt"],
)
- qv: Optional[Union[list[str], str]] = Field(
+ qv: list[str] | str | None = Field(
default=None,
title="Filter Value",
description="The value to filter by.",
@@ -45,13 +41,13 @@ class ValueFilterQueryParams(BaseModel):
class PaginationQueryParams(BaseModel):
"""Used to paginate a the request results by limiting and offsetting."""
- offset: Optional[int] = Field(
+ offset: int | None = Field(
default=0,
ge=0,
title="Offset",
description="Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item",
)
- limit: Optional[int] = Field(
+ limit: int | None = Field(
default=None,
ge=1,
title="Limit",
@@ -62,7 +58,7 @@ class PaginationQueryParams(BaseModel):
class FilterQueryParams(ValueFilterQueryParams, PaginationQueryParams):
"""Contains full filtering options to query elements, paginate and order them."""
- order: Optional[str] = Field(
+ order: str | None = Field(
default=None,
title="Order",
description=(
@@ -77,7 +73,7 @@ class FilterQueryParams(ValueFilterQueryParams, PaginationQueryParams):
class SerializationParams(BaseModel):
"""Contains common parameters for customizing model serialization."""
- view: Optional[str] = Field(
+ view: str | None = Field(
default=None,
title="View",
description=(
@@ -86,7 +82,7 @@ class SerializationParams(BaseModel):
),
examples=["summary"],
)
- keys: Optional[list[str]] = Field(
+ keys: list[str] | None = Field(
default=None,
title="Keys",
description=(
@@ -94,7 +90,7 @@ class SerializationParams(BaseModel):
"to the ones included in the `view`."
),
)
- default_view: Optional[str] = Field(
+ default_view: str | None = Field(
default=None,
title="Default View",
description="The item view that will be used in case none was specified.",
diff --git a/lib/galaxy/schema/agents.py b/lib/galaxy/schema/agents.py
index cd7855a9123..19b2fd3f1f7 100644
--- a/lib/galaxy/schema/agents.py
+++ b/lib/galaxy/schema/agents.py
@@ -5,7 +5,6 @@ Pydantic schemas for AI agent responses and requests.
from enum import Enum
from typing import (
Any,
- Optional,
)
from pydantic import (
@@ -69,7 +68,7 @@ class AgentResponse(BaseModel):
agent_type: str = Field(description="Type of agent that generated this response")
suggestions: list[ActionSuggestion] = Field(default_factory=list, description="Actionable suggestions")
metadata: dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
- reasoning: Optional[str] = Field(default=None, description="Explanation of the agent's reasoning")
+ reasoning: str | None = Field(default=None, description="Explanation of the agent's reasoning")
class AgentQueryRequest(BaseModel):
@@ -90,7 +89,7 @@ class AgentQueryResponse(BaseModel):
"""
response: AgentResponse = Field(description="The agent's response")
- processing_time: Optional[float] = Field(default=None, description="Time taken to process the query in seconds")
+ processing_time: float | None = Field(default=None, description="Time taken to process the query in seconds")
class AvailableAgent(BaseModel):
@@ -100,7 +99,7 @@ class AvailableAgent(BaseModel):
name: str = Field(description="Human-readable name")
description: str = Field(description="Description of the agent's capabilities")
enabled: bool = Field(description="Whether the agent is currently enabled")
- model: Optional[str] = Field(default=None, description="LLM model used by the agent")
+ model: str | None = Field(default=None, description="LLM model used by the agent")
specialties: list[str] = Field(default_factory=list, description="Areas of specialization")
@@ -126,16 +125,16 @@ class ErrorAnalysisRequest(BaseModel):
"""Request for error analysis."""
query: str = Field(description="Description of the error or problem")
- job_id: Optional[int] = Field(default=None, description="Galaxy job ID associated with the error")
- error_text: Optional[str] = Field(default=None, description="Specific error message text")
- tool_id: Optional[str] = Field(default=None, description="Tool that caused the error")
+ job_id: int | None = Field(default=None, description="Galaxy job ID associated with the error")
+ error_text: str | None = Field(default=None, description="Specific error message text")
+ tool_id: str | None = Field(default=None, description="Tool that caused the error")
class ErrorCategory(BaseModel):
"""Classification of error types."""
category: str = Field(description="Main error category")
- subcategory: Optional[str] = Field(default=None, description="More specific error subcategory")
+ subcategory: str | None = Field(default=None, description="More specific error subcategory")
severity: str = Field(description="Error severity level")
@@ -166,7 +165,7 @@ class QualityIssue(BaseModel):
severity: str = Field(description="Severity level")
description: str = Field(description="Detailed description of the issue")
suggested_fix: str = Field(description="Recommended solution")
- affected_records: Optional[int] = Field(default=None, description="Number of affected records")
+ affected_records: int | None = Field(default=None, description="Number of affected records")
class DatasetAnalysisResponse(BaseModel):
@@ -182,8 +181,8 @@ class DatasetAnalysisResponse(BaseModel):
class WorkflowOptimizationRequest(BaseModel):
"""Request for workflow optimization."""
- workflow_id: Optional[str] = Field(default=None, description="Galaxy workflow identifier")
- workflow_structure: Optional[dict[str, Any]] = Field(default=None, description="Workflow structure data")
+ workflow_id: str | None = Field(default=None, description="Galaxy workflow identifier")
+ workflow_structure: dict[str, Any] | None = Field(default=None, description="Workflow structure data")
performance_goals: list[str] = Field(default_factory=list, description="Optimization goals")
@@ -203,7 +202,7 @@ class WorkflowOptimizationResponse(BaseModel):
optimization_suggestions: list[OptimizationSuggestion] = Field(description="List of optimization suggestions")
performance_improvements: list[str] = Field(description="Expected performance improvements")
bottlenecks_identified: list[str] = Field(description="Identified bottlenecks")
- estimated_time_savings: Optional[str] = Field(default=None, description="Estimated time savings")
+ estimated_time_savings: str | None = Field(default=None, description="Estimated time savings")
confidence: ConfidenceLevel = Field(description="Confidence in the analysis")
@@ -224,7 +223,7 @@ class AgentStatus(BaseModel):
agent_type: str = Field(description="Type of agent")
enabled: bool = Field(description="Whether the agent is enabled")
health_status: str = Field(description="Health status (healthy, degraded, unavailable)")
- last_response_time: Optional[float] = Field(default=None, description="Last response time in seconds")
+ last_response_time: float | None = Field(default=None, description="Last response time in seconds")
error_rate: float = Field(description="Recent error rate")
model_info: dict[str, Any] = Field(default_factory=dict, description="Information about the underlying model")
@@ -243,5 +242,5 @@ class WorkflowReportResponse(BaseModel):
"""Response from the workflow report generation agent."""
report: str = Field(description="Generated markdown report for the workflow")
- total_tokens: Optional[int] = Field(default=None, description="Total tokens consumed by the generation")
- model: Optional[str] = Field(default=None, description="LLM model used to generate the report")
+ total_tokens: int | None = Field(default=None, description="Total tokens consumed by the generation")
+ model: str | None = Field(default=None, description="LLM model used to generate the report")
diff --git a/lib/galaxy/schema/citations.py b/lib/galaxy/schema/citations.py
index 1e0857c3f0a..d75d94f02fc 100644
--- a/lib/galaxy/schema/citations.py
+++ b/lib/galaxy/schema/citations.py
@@ -1,7 +1,6 @@
from typing import (
Annotated,
Literal,
- Union,
)
from pydantic import (
@@ -21,4 +20,4 @@ class CitationErrorResponse(BaseModel):
tool_id: str
-CitationItem = Annotated[Union[BibtexCitationResponse, CitationErrorResponse], Field(discriminator="format")]
+CitationItem = Annotated[BibtexCitationResponse | CitationErrorResponse, Field(discriminator="format")]
diff --git a/lib/galaxy/schema/credentials.py b/lib/galaxy/schema/credentials.py
index 41e8071c851..80b8794559b 100644
--- a/lib/galaxy/schema/credentials.py
+++ b/lib/galaxy/schema/credentials.py
@@ -2,7 +2,6 @@ from datetime import datetime
from typing import (
Annotated,
Literal,
- Optional,
)
from pydantic import (
@@ -30,7 +29,7 @@ class CredentialResponse(Model):
class VariableResponse(CredentialResponse):
value: Annotated[
- Optional[str],
+ str | None,
Field(
None,
description="The value of the variable (for variables, not secrets).",
@@ -141,7 +140,7 @@ class UserServiceCredentialsResponse(Model):
),
]
current_group_id: Annotated[
- Optional[EncodedDatabaseIdField],
+ EncodedDatabaseIdField | None,
Field(
None,
description="The ID of the currently active credential group.",
@@ -174,7 +173,7 @@ class ServiceCredentialsDefinition(Model):
),
]
label: Annotated[
- Optional[str],
+ str | None,
Field(
None,
description="A human-readable label for the service.",
@@ -207,7 +206,7 @@ class CredentialPayload(Model):
),
]
value: Annotated[
- Optional[str],
+ str | None,
Field(
None,
description="The value of the credential.",
@@ -296,7 +295,7 @@ class SelectCurrentGroupPayload(Model):
),
]
current_group_id: Annotated[
- Optional[DecodedDatabaseIdField],
+ DecodedDatabaseIdField | None,
Field(
None,
description="The ID of the group to set as current (None to unset).",
@@ -330,7 +329,7 @@ class SelectedGroup(Model):
class SelectedGroupResponse(Model):
id: Annotated[
- Optional[EncodedDatabaseIdField],
+ EncodedDatabaseIdField | None,
Field(
description="The encoded ID of the user credentials. If null, the group has been deleted by the user.",
),
@@ -373,7 +372,7 @@ class ServiceCredentialsContext(Model):
class ServiceCredentialsContextResponse(Model):
user_credentials_id: Annotated[
- Optional[EncodedDatabaseIdField],
+ EncodedDatabaseIdField | None,
Field(
description="The encoded ID of the user credentials. If null, the credentials have been deleted by the user.",
),
diff --git a/lib/galaxy/schema/fetch_data.py b/lib/galaxy/schema/fetch_data.py
index 383ac2b48ab..b4466782060 100644
--- a/lib/galaxy/schema/fetch_data.py
+++ b/lib/galaxy/schema/fetch_data.py
@@ -4,7 +4,6 @@ from typing import (
Annotated,
Any,
Literal,
- Optional,
Union,
)
@@ -91,24 +90,24 @@ class LibraryFolderDestination(FetchBaseModel):
class BaseCollectionTarget(BaseFetchDataTarget):
destination: HdcaDestination
- collection_type: Optional[str] = None
- tags: Optional[list[str]] = None
- name: Optional[str] = None
- column_definitions: Optional[SampleSheetColumnDefinitions] = None
- rows: Optional[dict[str, SampleSheetRow]] = None
+ collection_type: str | None = None
+ tags: list[str] | None = None
+ name: str | None = None
+ column_definitions: SampleSheetColumnDefinitions | None = None
+ rows: dict[str, SampleSheetRow] | None = None
class LibraryDestination(FetchBaseModel):
type: Literal["library"]
name: str = Field(..., description="Must specify a library name")
- description: Optional[str] = Field(None, description="Description for library to create")
- synopsis: Optional[str] = Field(None, description="Description for library to create")
+ description: str | None = Field(None, description="Description for library to create")
+ synopsis: str | None = Field(None, description="Description for library to create")
class ExtraFiles(FetchBaseModel):
- items_from: Optional[str] = None
+ items_from: str | None = None
src: Src
- fuzzy_root: Optional[bool] = Field(
+ fuzzy_root: bool | None = Field(
True,
description="Prevent Galaxy from checking for a single file in a directory and re-interpreting the archive",
)
@@ -122,28 +121,28 @@ class FetchDatasetHash(Model):
class BaseDataElement(FetchBaseModel):
- name: Optional[CoercedStringType] = None
+ name: CoercedStringType | None = None
dbkey: str = Field("?", description=HELP_TERMS.get_term("galaxy.dataFetch.dbkey"))
- info: Optional[str] = Field(None, description=HELP_TERMS.get_term("galaxy.dataFetch.info"))
+ info: str | None = Field(None, description=HELP_TERMS.get_term("galaxy.dataFetch.info"))
ext: str = Field("auto", description=HELP_TERMS.get_term("galaxy.dataFetch.ext"))
space_to_tab: bool = Field(False, description=HELP_TERMS.get_term("galaxy.dataFetch.space_to_tab"))
to_posix_lines: bool = Field(False, description=HELP_TERMS.get_term("galaxy.dataFetch.to_posix_lines"))
deferred: bool = Field(False, description=HELP_TERMS.get_term("galaxy.dataFetch.deferred"))
- tags: Optional[list[str]] = Field(None, description=HELP_TERMS.get_term("galaxy.dataFetch.tags"))
- created_from_basename: Optional[str] = None
- extra_files: Optional[ExtraFiles] = None
+ tags: list[str] | None = Field(None, description=HELP_TERMS.get_term("galaxy.dataFetch.tags"))
+ created_from_basename: str | None = None
+ extra_files: ExtraFiles | None = None
auto_decompress: bool = AutoDecompressField
- items_from: Optional[ElementsFromType] = Field(None, validation_alias=AliasChoices("items_from", "elements_from"))
- collection_type: Optional[str] = None
- MD5: Optional[str] = Field(None, description=HELP_TERMS.get_term("galaxy.dataFetch.MD5"))
- SHA1: Optional[str] = Field(None, alias="SHA-1", description=HELP_TERMS.get_term("galaxy.dataFetch.SHA1"))
- SHA256: Optional[str] = Field(None, alias="SHA-256", description=HELP_TERMS.get_term("galaxy.dataFetch.SHA256"))
- SHA512: Optional[str] = Field(None, alias="SHA-512", description=HELP_TERMS.get_term("galaxy.dataFetch.SHA512"))
- hashes: Optional[list[FetchDatasetHash]] = None
- description: Optional[str] = None
+ items_from: ElementsFromType | None = Field(None, validation_alias=AliasChoices("items_from", "elements_from"))
+ collection_type: str | None = None
+ MD5: str | None = Field(None, description=HELP_TERMS.get_term("galaxy.dataFetch.MD5"))
+ SHA1: str | None = Field(None, alias="SHA-1", description=HELP_TERMS.get_term("galaxy.dataFetch.SHA1"))
+ SHA256: str | None = Field(None, alias="SHA-256", description=HELP_TERMS.get_term("galaxy.dataFetch.SHA256"))
+ SHA512: str | None = Field(None, alias="SHA-512", description=HELP_TERMS.get_term("galaxy.dataFetch.SHA512"))
+ hashes: list[FetchDatasetHash] | None = None
+ description: str | None = None
model_config = ConfigDict(extra="forbid")
# It'd be nice to restrict this to just the top level and only if creating a collection
- row: Optional[SampleSheetRow] = None
+ row: SampleSheetRow | None = None
class FileDataElement(BaseDataElement):
@@ -158,51 +157,51 @@ class PastedDataElement(BaseDataElement):
class UrlDataElement(BaseDataElement):
src: Literal["url"]
url: str = Field(..., description="URL to upload")
- headers: Optional[dict[str, str]] = Field(None, description="Optional headers to include in the URL fetch request")
+ headers: dict[str, str] | None = Field(None, description="Optional headers to include in the URL fetch request")
class ServerDirElement(BaseDataElement):
src: Literal["server_dir"]
server_dir: str
- link_data_only: Optional[bool] = None
+ link_data_only: bool | None = None
class FtpImportElement(BaseDataElement):
src: Literal["ftp_import"]
ftp_path: str
- collection_type: Optional[str] = None
+ collection_type: str | None = None
class ItemsFromModel(Model):
src: ItemsFromSrc
- path: Optional[str] = None
- ftp_path: Optional[str] = None
- server_dir: Optional[str] = None
- url: Optional[str] = None
+ path: str | None = None
+ ftp_path: str | None = None
+ server_dir: str | None = None
+ url: str | None = None
class FtpImportTarget(BaseCollectionTarget):
src: Literal["ftp_import"]
ftp_path: str
- items_from: Optional[ElementsFromType] = Field(None, validation_alias=AliasChoices("items_from", "elements_from"))
+ items_from: ElementsFromType | None = Field(None, validation_alias=AliasChoices("items_from", "elements_from"))
class PathDataElement(BaseDataElement):
src: Literal["path"]
path: str
- items_from: Optional[ElementsFromType] = Field(None, validation_alias=AliasChoices("items_from", "elements_from"))
- link_data_only: Optional[bool] = None
+ items_from: ElementsFromType | None = Field(None, validation_alias=AliasChoices("items_from", "elements_from"))
+ link_data_only: bool | None = None
class CompositeDataElement(BaseDataElement):
src: Literal["composite"]
composite: "CompositeItems"
- metadata: Optional[dict[str, Any]] = None
+ metadata: dict[str, Any] | None = None
class CompositeItems(FetchBaseModel):
elements: list[
- Union[FileDataElement, PastedDataElement, UrlDataElement, PathDataElement, ServerDirElement, FtpImportElement]
+ FileDataElement | PastedDataElement | UrlDataElement | PathDataElement | ServerDirElement | FtpImportElement
] = Field(..., validation_alias=AliasChoices("elements", "items"))
@@ -216,30 +215,26 @@ class NestedElement(BaseDataElement):
AnyElement = Annotated[
- Union[
- FileDataElement,
- PastedDataElement,
- UrlDataElement,
- PathDataElement,
- ServerDirElement,
- FtpImportElement,
- CompositeDataElement,
- ],
+ FileDataElement
+ | PastedDataElement
+ | UrlDataElement
+ | PathDataElement
+ | ServerDirElement
+ | FtpImportElement
+ | CompositeDataElement,
Field(default_factory=None, discriminator="src"),
]
# Seems to be a bug in pydantic ... can't reuse AnyElement in more than one model
AnyElement2 = Annotated[
- Union[
- FileDataElement,
- PastedDataElement,
- UrlDataElement,
- PathDataElement,
- ServerDirElement,
- FtpImportElement,
- CompositeDataElement,
- ],
+ FileDataElement
+ | PastedDataElement
+ | UrlDataElement
+ | PathDataElement
+ | ServerDirElement
+ | FtpImportElement
+ | CompositeDataElement,
Field(default_factory=None, discriminator="src"),
]
@@ -247,11 +242,11 @@ NestedElement.model_rebuild()
class BaseDataTarget(BaseFetchDataTarget):
- destination: Union[HdaDestination, LibraryFolderDestination, LibraryDestination] = Field(..., discriminator="type")
+ destination: HdaDestination | LibraryFolderDestination | LibraryDestination = Field(..., discriminator="type")
class DataElementsTarget(BaseDataTarget):
- elements: list[Union[AnyElement, NestedElement]] = Field(..., validation_alias=AliasChoices("elements", "items"))
+ elements: list[AnyElement | NestedElement] = Field(..., validation_alias=AliasChoices("elements", "items"))
class DataElementsFromTarget(BaseDataTarget, ItemsFromModel):
@@ -259,7 +254,7 @@ class DataElementsFromTarget(BaseDataTarget, ItemsFromModel):
class HdcaDataItemsTarget(BaseCollectionTarget):
- elements: list[Union[AnyElement2, NestedElement]] = Field(..., validation_alias=AliasChoices("elements", "items"))
+ elements: list[AnyElement2 | NestedElement] = Field(..., validation_alias=AliasChoices("elements", "items"))
class HdcaDataItemsFromTarget(BaseCollectionTarget, ItemsFromModel):
@@ -273,12 +268,12 @@ class FilesPayload(Model):
class BaseDataPayload(FetchBaseModel):
history_id: DecodedDatabaseIdField
- preferred_object_store_id: Optional[str] = Field(
+ preferred_object_store_id: str | None = Field(
None,
description="Optional preferred storage location id used when creating fetched datasets.",
)
model_config = ConfigDict(extra="allow")
- landing_uuid: Optional[UUID4] = None
+ landing_uuid: UUID4 | None = None
@field_validator("targets", mode="before", check_fields=False)
@classmethod
@@ -289,13 +284,7 @@ class BaseDataPayload(FetchBaseModel):
Targets = list[
- Union[
- DataElementsTarget,
- HdcaDataItemsTarget,
- DataElementsFromTarget,
- HdcaDataItemsFromTarget,
- FtpImportTarget,
- ]
+ DataElementsTarget | HdcaDataItemsTarget | DataElementsFromTarget | HdcaDataItemsFromTarget | FtpImportTarget
]
@@ -307,7 +296,7 @@ class FetchDataPayload(BaseDataPayload):
class FetchDataFormPayload(BaseDataPayload):
- targets: Union[Json[Targets], Targets]
+ targets: Json[Targets] | Targets
class DataLandingRequestState(Model):
@@ -323,17 +312,17 @@ FileOrCollectionRequestsAdapter = TypeAdapter(FileOrCollectionRequests)
# via the tool API so we have a more specific model here.
class CreateDataLandingPayload(Model):
request_state: DataLandingRequestState
- client_secret: Optional[str] = None
+ client_secret: str | None = None
public: bool = False
- origin: Optional[HttpUrl] = None
+ origin: HttpUrl | None = None
model_config = ConfigDict(extra="forbid")
class CreateFileLandingPayload(Model):
request_state: FileOrCollectionRequests
- client_secret: Optional[str] = None
+ client_secret: str | None = None
public: bool = False
- origin: Optional[HttpUrl] = None
+ origin: HttpUrl | None = None
model_config = ConfigDict(extra="forbid")
diff --git a/lib/galaxy/schema/fields.py b/lib/galaxy/schema/fields.py
index 75428e18038..5f76de9bf32 100644
--- a/lib/galaxy/schema/fields.py
+++ b/lib/galaxy/schema/fields.py
@@ -1,5 +1,6 @@
import re
from collections.abc import Callable
+from types import UnionType
from typing import (
Annotated,
get_args,
@@ -145,7 +146,7 @@ def literal_to_value(arg):
def is_optional(field):
args = get_args(field)
- return get_origin(field) is Union and len(args) == 2 and type(None) in args
+ return get_origin(field) in (Union, UnionType) and len(args) == 2 and type(None) in args
def ModelClassField(default_value):
diff --git a/lib/galaxy/schema/groups.py b/lib/galaxy/schema/groups.py
index 0cbf11ca35d..8d14f4f6e73 100644
--- a/lib/galaxy/schema/groups.py
+++ b/lib/galaxy/schema/groups.py
@@ -1,6 +1,5 @@
from typing import (
Literal,
- Optional,
)
from pydantic import (
@@ -38,11 +37,11 @@ class GroupResponse(Model, WithModelClass):
...,
title="URL for the group",
)
- roles_url: Optional[str] = Field(
+ roles_url: str | None = Field(
None,
title="URL for the roles of the group",
)
- users_url: Optional[str] = Field(
+ users_url: str | None = Field(
None,
title="URL for the users of the group",
)
@@ -84,11 +83,11 @@ class GroupUpdatePayload(Model):
...,
title="name of the group",
)
- user_ids: Optional[list[DecodedDatabaseIdField]] = Field(
+ user_ids: list[DecodedDatabaseIdField] | None = Field(
None,
title="user IDs",
)
- role_ids: Optional[list[DecodedDatabaseIdField]] = Field(
+ role_ids: list[DecodedDatabaseIdField] | None = Field(
None,
title="role IDs",
)
diff --git a/lib/galaxy/schema/help.py b/lib/galaxy/schema/help.py
index 48e43e6b641..36c980d2cfc 100644
--- a/lib/galaxy/schema/help.py
+++ b/lib/galaxy/schema/help.py
@@ -1,7 +1,6 @@
from typing import (
Annotated,
Any,
- Optional,
)
from pydantic import (
@@ -32,14 +31,14 @@ class HelpForumPost(HelpTempBaseModel):
"""Model for a post in the help forum."""
id: Annotated[int, Field(description="The ID of the post.")]
- name: Annotated[Optional[str], Field(description="The name of the post.")]
- username: Annotated[Optional[str], Field(description="The username of the post author.")]
- avatar_template: Annotated[Optional[str], Field(description="The avatar template of the user.")]
- created_at: Annotated[Optional[str], Field(description="The creation date of the post.")]
- like_count: Annotated[Optional[int], Field(description="The number of likes of the post.")]
- blurb: Annotated[Optional[str], Field(description="The blurb of the post.")]
- post_number: Annotated[Optional[int], Field(description="The post number of the post.")]
- topic_id: Annotated[Optional[int], Field(description="The ID of the topic of the post.")]
+ name: Annotated[str | None, Field(description="The name of the post.")]
+ username: Annotated[str | None, Field(description="The username of the post author.")]
+ avatar_template: Annotated[str | None, Field(description="The avatar template of the user.")]
+ created_at: Annotated[str | None, Field(description="The creation date of the post.")]
+ like_count: Annotated[int | None, Field(description="The number of likes of the post.")]
+ blurb: Annotated[str | None, Field(description="The blurb of the post.")]
+ post_number: Annotated[int | None, Field(description="The post number of the post.")]
+ topic_id: Annotated[int | None, Field(description="The ID of the topic of the post.")]
class HelpForumTopic(Model):
@@ -59,14 +58,14 @@ class HelpForumTopic(Model):
archetype: Annotated[Any, Field(description="The archetype of the topic.")]
unseen: Annotated[bool, Field(description="Whether the topic is unseen.")]
pinned: Annotated[bool, Field(description="Whether the topic is pinned.")]
- unpinned: Annotated[Optional[bool], Field(description="Whether the topic is unpinned.")] = None
+ unpinned: Annotated[bool | None, Field(description="Whether the topic is unpinned.")] = None
visible: Annotated[bool, Field(description="Whether the topic is visible.")]
closed: Annotated[bool, Field(description="Whether the topic is closed.")]
archived: Annotated[bool, Field(description="Whether the topic is archived.")]
- bookmarked: Annotated[Optional[bool], Field(description="Whether the topic is bookmarked.")] = None
- liked: Annotated[Optional[bool], Field(description="Whether the topic is liked.")] = None
+ bookmarked: Annotated[bool | None, Field(description="Whether the topic is bookmarked.")] = None
+ liked: Annotated[bool | None, Field(description="Whether the topic is liked.")] = None
tags: Annotated[list[HelpForumTag], Field(description="The tags of the topic.")]
- tags_descriptions: Annotated[Optional[Any], Field(description="The descriptions of the tags of the topic.")] = None
+ tags_descriptions: Annotated[Any | None, Field(description="The descriptions of the tags of the topic.")] = None
category_id: Annotated[int, Field(description="The ID of the category of the topic.")]
has_accepted_answer: Annotated[bool, Field(description="Whether the topic has an accepted answer.")]
@@ -101,23 +100,19 @@ class HelpForumSearchResponse(Model):
This model is based on the Discourse API response for the search endpoint.
"""
- posts: Annotated[Optional[list[HelpForumPost]], Field(description="The list of posts returned by the search.")] = (
- None
- )
- topics: Annotated[
- Optional[list[HelpForumTopic]], Field(description="The list of topics returned by the search.")
- ] = None
- users: Annotated[Optional[list[HelpForumUser]], Field(description="The list of users returned by the search.")] = (
+ posts: Annotated[list[HelpForumPost] | None, Field(description="The list of posts returned by the search.")] = None
+ topics: Annotated[list[HelpForumTopic] | None, Field(description="The list of topics returned by the search.")] = (
None
)
+ users: Annotated[list[HelpForumUser] | None, Field(description="The list of users returned by the search.")] = None
categories: Annotated[
- Optional[list[HelpForumCategory]],
+ list[HelpForumCategory] | None,
Field(description="The list of categories returned by the search."),
] = None
- tags: Annotated[Optional[list[HelpForumTag]], Field(description="The list of tags returned by the search.")] = None
- groups: Annotated[
- Optional[list[HelpForumGroup]], Field(description="The list of groups returned by the search.")
- ] = None
+ tags: Annotated[list[HelpForumTag] | None, Field(description="The list of tags returned by the search.")] = None
+ groups: Annotated[list[HelpForumGroup] | None, Field(description="The list of groups returned by the search.")] = (
+ None
+ )
grouped_search_result: Annotated[
- Optional[HelpForumGroupedSearchResult], Field(description="The grouped search result.")
+ HelpForumGroupedSearchResult | None, Field(description="The grouped search result.")
] = None
diff --git a/lib/galaxy/schema/history.py b/lib/galaxy/schema/history.py
index 9b9a5c4985f..37900c323a3 100644
--- a/lib/galaxy/schema/history.py
+++ b/lib/galaxy/schema/history.py
@@ -1,7 +1,6 @@
from datetime import datetime
from typing import (
Literal,
- Optional,
)
from pydantic import (
@@ -22,17 +21,15 @@ HistorySortByEnum = Literal["create_time", "name", "update_time", "username"]
class HistoryIndexQueryPayload(Model):
- show_own: Optional[bool] = None
- show_published: Optional[bool] = None
- show_shared: Optional[bool] = None
- show_archived: Optional[bool] = None
+ show_own: bool | None = None
+ show_published: bool | None = None
+ show_shared: bool | None = None
+ show_archived: bool | None = None
sort_by: HistorySortByEnum = Field("update_time", title="Sort By", description="Sort by this attribute.")
- sort_desc: Optional[bool] = Field(default=True, title="Sort descending", description="Sort in descending order.")
- search: Optional[str] = Field(default=None, title="Filter text", description="Freetext to search.")
- limit: Optional[int] = Field(
- default=100, lt=1000, title="Limit", description="Maximum number of entries to return."
- )
- offset: Optional[int] = Field(default=0, title="Offset", description="Number of entries to skip.")
+ sort_desc: bool | None = Field(default=True, title="Sort descending", description="Sort in descending order.")
+ search: str | None = Field(default=None, title="Filter text", description="Freetext to search.")
+ limit: int | None = Field(default=100, lt=1000, title="Limit", description="Maximum number of entries to return.")
+ offset: int | None = Field(default=0, title="Offset", description="Number of entries to skip.")
class HistoryQueryResult(Model):
@@ -43,7 +40,7 @@ class HistoryQueryResult(Model):
title="ID",
description="Encoded ID of the History.",
)
- annotation: Optional[str] = Field(
+ annotation: str | None = Field(
default=None,
title="Annotation",
description="The annotation of this History.",
@@ -63,7 +60,7 @@ class HistoryQueryResult(Model):
title="Published",
description="Whether this History has been published.",
)
- tags: Optional[TagCollection] = Field(
+ tags: TagCollection | None = Field(
...,
title="Tags",
description="A list of tags to add to this item.",
@@ -72,8 +69,8 @@ class HistoryQueryResult(Model):
title="Name",
description="The name of the History.",
)
- create_time: Optional[datetime] = CreateTimeField
- update_time: Optional[datetime] = UpdateTimeField
+ create_time: datetime | None = CreateTimeField
+ update_time: datetime | None = UpdateTimeField
class HistoryQueryResultList(RootModel):
diff --git a/lib/galaxy/schema/history_graph.py b/lib/galaxy/schema/history_graph.py
index e9a9324b46c..a21e073665d 100644
--- a/lib/galaxy/schema/history_graph.py
+++ b/lib/galaxy/schema/history_graph.py
@@ -1,6 +1,5 @@
from typing import (
Literal,
- Optional,
)
from pydantic import (
@@ -28,16 +27,16 @@ class NodeRef(BaseModel):
class GraphNode(BaseModel):
src: NodeSrc
id: str
- name: Optional[str] = None
- hid: Optional[int] = None
- state: Optional[str] = None
- extension: Optional[str] = None
- collection_type: Optional[str] = None
- deleted: Optional[bool] = None
- visible: Optional[bool] = None
- tool_id: Optional[str] = None
- tool_name: Optional[str] = None
- job_state_summary: Optional[dict[str, int]] = None
+ name: str | None = None
+ hid: int | None = None
+ state: str | None = None
+ extension: str | None = None
+ collection_type: str | None = None
+ deleted: bool | None = None
+ visible: bool | None = None
+ tool_id: str | None = None
+ tool_name: str | None = None
+ job_state_summary: dict[str, int] | None = None
@property
def ref(self) -> NodeRef:
@@ -59,7 +58,7 @@ class GraphEdge(BaseModel):
class TruncationInfo(BaseModel):
item_count_capped: bool = False
scope_type: Literal["recent", "seed_centered"] = "recent"
- seed_in_scope: Optional[bool] = None
+ seed_in_scope: bool | None = None
class HistoryGraphResponse(BaseModel):
diff --git a/lib/galaxy/schema/invocation.py b/lib/galaxy/schema/invocation.py
index 2e568396f98..373e1d5dd42 100644
--- a/lib/galaxy/schema/invocation.py
+++ b/lib/galaxy/schema/invocation.py
@@ -5,8 +5,6 @@ from typing import (
Any,
Generic,
Literal,
- Optional,
- Union,
)
from pydantic import (
@@ -117,8 +115,8 @@ class CancelReason(str, Enum):
class InvocationMessageBase(GenericModel):
- reason: Union[CancelReason, FailureReason, WarningReason]
- workflow_step_index_path: Optional[list[int]] = Field(
+ reason: CancelReason | FailureReason | WarningReason
+ workflow_step_index_path: list[int] | None = Field(
None,
description="Path of workflow step IDs from parent workflow through subworkflows (excludes the failing step itself).",
)
@@ -154,7 +152,7 @@ class GenericInvocationFailureDatasetFailed(InvocationFailureMessageBase[Databas
hda_id: DatabaseIdT = Field(
..., title="HistoryDatasetAssociation ID", description="HistoryDatasetAssociation ID that relates to failure."
)
- dependent_workflow_step_id: Optional[int] = Field(None, description="Workflow step id of step that caused failure.")
+ dependent_workflow_step_id: int | None = Field(None, description="Workflow step id of step that caused failure.")
class GenericInvocationFailureCollectionFailed(InvocationFailureMessageBase[DatabaseIdT], Generic[DatabaseIdT]):
@@ -195,7 +193,7 @@ class GenericInvocationFailureExpressionEvaluationFailed(
InvocationFailureMessageBase[DatabaseIdT], Generic[DatabaseIdT]
):
reason: Literal[FailureReason.expression_evaluation_failed]
- details: Optional[str] = Field(None, description="May contain details to help troubleshoot this problem.")
+ details: str | None = Field(None, description="May contain details to help troubleshoot this problem.")
class GenericInvocationFailureWhenNotBoolean(InvocationFailureMessageBase[DatabaseIdT], Generic[DatabaseIdT]):
@@ -205,15 +203,15 @@ class GenericInvocationFailureWhenNotBoolean(InvocationFailureMessageBase[Databa
class GenericInvocationUnexpectedFailure(InvocationMessageBase, Generic[DatabaseIdT]):
reason: Literal[FailureReason.unexpected_failure]
- details: Optional[str] = Field(None, description="May contains details to help troubleshoot this problem.")
- workflow_step_id: Optional[int] = Field(
+ details: str | None = Field(None, description="May contains details to help troubleshoot this problem.")
+ workflow_step_id: int | None = Field(
None, description="Workflow step id of step that failed.", validation_alias="workflow_step_index"
)
class GenericInvocationWarning(InvocationMessageBase, Generic[DatabaseIdT]):
reason: WarningReason = Field(..., title="Failure Reason", description="Reason for warning")
- workflow_step_id: Optional[int] = Field(
+ workflow_step_id: int | None = Field(
None, title="Workflow step id of step that caused a warning.", validation_alias="workflow_step_index"
)
@@ -240,12 +238,12 @@ class GenericInvocationFailureWorkflowParameterInvalid(InvocationFailureMessageB
class GenericInvocationFailureStepInputDeleted(InvocationFailureMessageBase[DatabaseIdT], Generic[DatabaseIdT]):
reason: Literal[FailureReason.step_input_deleted]
- hda_id: Optional[DatabaseIdT] = Field(
+ hda_id: DatabaseIdT | None = Field(
None,
title="HistoryDatasetAssociation ID",
description="HistoryDatasetAssociation ID of the deleted dataset, if applicable.",
)
- hdca_id: Optional[DatabaseIdT] = Field(
+ hdca_id: DatabaseIdT | None = Field(
None,
title="HistoryDatasetCollectionAssociation ID",
description="HistoryDatasetCollectionAssociation ID of the deleted collection, if applicable.",
@@ -267,21 +265,22 @@ InvocationWarningWorkflowOutputNotFound = GenericInvocationEvaluationWarningWork
InvocationFailureWorkflowParameterInvalid = GenericInvocationFailureWorkflowParameterInvalid[int]
InvocationFailureStepInputDeleted = GenericInvocationFailureStepInputDeleted[int]
-InvocationMessageUnion = Union[
- InvocationCancellationReviewFailed,
- InvocationCancellationHistoryDeleted,
- InvocationCancellationUserRequest,
- InvocationFailureDatasetFailed,
- InvocationFailureCollectionFailed,
- InvocationFailureJobFailed,
- InvocationFailureOutputNotFound,
- InvocationFailureExpressionEvaluationFailed,
- InvocationFailureWhenNotBoolean,
- InvocationUnexpectedFailure,
- InvocationWarningWorkflowOutputNotFound,
- InvocationFailureWorkflowParameterInvalid,
- InvocationFailureStepInputDeleted,
-]
+InvocationMessageUnion = (
+ InvocationCancellationReviewFailed
+ | InvocationCancellationHistoryDeleted
+ | InvocationCancellationUserRequest
+ | InvocationFailureDatasetFailed
+ | InvocationFailureCollectionFailed
+ | InvocationFailureJobFailed
+ | InvocationFailureOutputNotFound
+ | InvocationFailureExpressionEvaluationFailed
+ | InvocationFailureWhenNotBoolean
+ | InvocationUnexpectedFailure
+ | InvocationWarningWorkflowOutputNotFound
+ | InvocationFailureWorkflowParameterInvalid
+ | InvocationFailureStepInputDeleted
+)
+
InvocationCancellationReviewFailedResponseModel = GenericInvocationCancellationReviewFailed[EncodedDatabaseIdField]
InvocationCancellationHistoryDeletedResponseModel = GenericInvocationCancellationHistoryDeleted[EncodedDatabaseIdField]
@@ -304,21 +303,19 @@ InvocationFailureWorkflowParameterInvalidResponseModel = GenericInvocationFailur
InvocationFailureStepInputDeletedResponseModel = GenericInvocationFailureStepInputDeleted[EncodedDatabaseIdField]
_InvocationMessageResponseUnion = Annotated[
- Union[
- InvocationCancellationReviewFailedResponseModel,
- InvocationCancellationHistoryDeletedResponseModel,
- InvocationCancellationUserRequestResponseModel,
- InvocationFailureDatasetFailedResponseModel,
- InvocationFailureCollectionFailedResponseModel,
- InvocationFailureJobFailedResponseModel,
- InvocationFailureOutputNotFoundResponseModel,
- InvocationFailureExpressionEvaluationFailedResponseModel,
- InvocationFailureWhenNotBooleanResponseModel,
- InvocationUnexpectedFailureResponseModel,
- InvocationWarningWorkflowOutputNotFoundResponseModel,
- InvocationFailureWorkflowParameterInvalidResponseModel,
- InvocationFailureStepInputDeletedResponseModel,
- ],
+ InvocationCancellationReviewFailedResponseModel
+ | InvocationCancellationHistoryDeletedResponseModel
+ | InvocationCancellationUserRequestResponseModel
+ | InvocationFailureDatasetFailedResponseModel
+ | InvocationFailureCollectionFailedResponseModel
+ | InvocationFailureJobFailedResponseModel
+ | InvocationFailureOutputNotFoundResponseModel
+ | InvocationFailureExpressionEvaluationFailedResponseModel
+ | InvocationFailureWhenNotBooleanResponseModel
+ | InvocationUnexpectedFailureResponseModel
+ | InvocationWarningWorkflowOutputNotFoundResponseModel
+ | InvocationFailureWorkflowParameterInvalidResponseModel
+ | InvocationFailureStepInputDeletedResponseModel,
Field(discriminator="reason"),
]
@@ -360,7 +357,7 @@ class InvocationStepOutput(Model):
title="Dataset ID",
description="Dataset ID of the workflow step output.",
)
- uuid: Optional[UUID4] = Field(
+ uuid: UUID4 | None = Field(
None,
title="UUID",
description="Universal unique identifier of the workflow step output dataset.",
@@ -385,9 +382,9 @@ class InvocationStep(Model, WithModelClass):
model_class: INVOCATION_STEP_MODEL_CLASS = ModelClassField(INVOCATION_STEP_MODEL_CLASS)
id: Annotated[EncodedDatabaseIdField, Field(..., title="Invocation Step ID")]
- update_time: Optional[datetime] = schema.UpdateTimeField
+ update_time: datetime | None = schema.UpdateTimeField
job_id: Annotated[
- Optional[EncodedDatabaseIdField],
+ EncodedDatabaseIdField | None,
Field(
default=None,
title="Job ID",
@@ -403,30 +400,30 @@ class InvocationStep(Model, WithModelClass):
),
]
subworkflow_invocation_id: Annotated[
- Optional[EncodedDatabaseIdField],
+ EncodedDatabaseIdField | None,
Field(
default=None,
title="Subworkflow invocation ID",
description="The encoded ID of the subworkflow invocation.",
),
]
- state: Optional[Union[InvocationStepState, JobState]] = Field(
+ state: InvocationStepState | JobState | None = Field(
default=None,
title="State of the invocation step",
description="Describes where in the scheduling process the workflow invocation step is.",
)
- action: Optional[bool] = InvocationStepActionField
+ action: bool | None = InvocationStepActionField
order_index: int = Field(
...,
title="Order index",
description="The index of the workflow step in the workflow.",
)
- workflow_step_label: Optional[str] = Field(
+ workflow_step_label: str | None = Field(
default=None,
title="Step label",
description="The label of the workflow step",
)
- workflow_step_uuid: Optional[UUID4] = Field(
+ workflow_step_uuid: UUID4 | None = Field(
None,
title="UUID",
description="Universal unique identifier of the workflow step.",
@@ -446,7 +443,7 @@ class InvocationStep(Model, WithModelClass):
title="Jobs",
description="Jobs associated with the workflow invocation step.",
)
- implicit_collection_jobs_id: Optional[EncodedDatabaseIdField] = Field(
+ implicit_collection_jobs_id: EncodedDatabaseIdField | None = Field(
None,
title="Implicit Collection Jobs ID",
description="The implicit collection job ID associated with the workflow invocation step.",
@@ -461,12 +458,12 @@ class InvocationReport(Model, WithModelClass):
title="Render format",
description="Format of the invocation report.",
)
- markdown: Optional[str] = Field(
+ markdown: str | None = Field(
default=None,
title="Markdown",
description="Raw galaxy-flavored markdown contents of the report.",
)
- invocation_markdown: Optional[str] = Field(
+ invocation_markdown: str | None = Field(
default=None,
title="Markdown",
description="Raw galaxy-flavored markdown contents of the report.",
@@ -487,10 +484,10 @@ class InvocationReport(Model, WithModelClass):
title="Title",
description="The name of the report.",
)
- generate_time: Optional[str] = schema.GenerateTimeField
- generate_version: Optional[str] = schema.GenerateVersionField
+ generate_time: str | None = schema.GenerateTimeField
+ generate_version: str | None = schema.GenerateVersionField
- errors: Optional[list[dict[str, Any]]] = Field(
+ errors: list[dict[str, Any]] | None = Field(
default=None,
title="Errors",
description="Errors associated with the invocation.",
@@ -503,12 +500,12 @@ class ReportInvocationErrorPayload(Model):
title="Invocation ID",
description="The ID of the invocation related to the error.",
)
- email: Optional[str] = Field(
+ email: str | None = Field(
default=None,
title="Email",
description="Email address for communication with the user. Only required for anonymous users.",
)
- message: Optional[str] = Field(
+ message: str | None = Field(
default=None,
title="Message",
description="The optional message sent with the error report.",
@@ -520,7 +517,7 @@ class InvocationUpdatePayload(Model):
class InvocationIOBase(Model):
- id: Optional[EncodedDatabaseIdField] = Field(
+ id: EncodedDatabaseIdField | None = Field(
default=None, title="ID", description="The encoded ID of the dataset/dataset collection."
)
workflow_step_id: EncodedDatabaseIdField = Field(
@@ -531,12 +528,12 @@ class InvocationIOBase(Model):
class InvocationInput(InvocationIOBase):
- label: Optional[str] = Field(
+ label: str | None = Field(
default=None,
title="Label",
description="Label of the workflow step associated with the input dataset/dataset collection.",
)
- src: Union[Literal[DataItemSourceType.hda], Literal[DataItemSourceType.hdca]] = Field(
+ src: Literal[DataItemSourceType.hda] | Literal[DataItemSourceType.hdca] = Field(
default=..., title="Source", description="Source type of the input dataset/dataset collection."
)
@@ -582,16 +579,16 @@ class WorkflowInvocationCollectionView(Model, WithModelClass):
description="The encoded ID of the history associated with the invocation.",
)
# The uuid version here is 1, which deviates from the other UUIDs used as they are version 4.
- uuid: Optional[Union[UUID4, UUID1]] = Field(
+ uuid: UUID4 | UUID1 | None = Field(
default=None, title="UUID", description="Universal unique identifier of the workflow invocation."
)
state: InvocationState = Field(default=..., title="Invocation state", description="State of workflow invocation.")
- landing_uuid: Optional[UUID4] = Field(
+ landing_uuid: UUID4 | None = Field(
default=None,
title="Landing UUID",
description="The UUID of the workflow landing request associated with this invocation.",
)
- on_complete: Optional[list[dict[str, Any]]] = Field(
+ on_complete: list[dict[str, Any]] | None = Field(
default=None,
title="On Complete Actions",
description="Actions to be executed when the workflow invocation completes.",
@@ -626,9 +623,7 @@ class WorkflowInvocationElementView(WorkflowInvocationCollectionView):
class WorkflowInvocationResponse(RootModel):
- root: Annotated[
- Union[WorkflowInvocationElementView, WorkflowInvocationCollectionView], Field(union_mode="left_to_right")
- ]
+ root: Annotated[WorkflowInvocationElementView | WorkflowInvocationCollectionView, Field(union_mode="left_to_right")]
class WorkflowInvocationRequestModel(Model):
@@ -650,18 +645,18 @@ class WorkflowInvocationRequestModel(Model):
title="Inputs by",
description=INPUTS_BY_DESCRIPTION,
)
- replacement_params: Optional[dict[str, Any]] = ReplacementParametersField
- resource_params: Optional[dict[str, Any]] = ResourceParametersField
+ replacement_params: dict[str, Any] | None = ReplacementParametersField
+ resource_params: dict[str, Any] | None = ResourceParametersField
use_cached_job: bool = UseCachedJobField
- preferred_object_store_id: Optional[str] = PreferredObjectStoreIdField
- preferred_intermediate_object_store_id: Optional[str] = PreferredIntermediateObjectStoreIdField
- preferred_outputs_object_store_id: Optional[str] = PreferredOutputsObjectStoreIdField
+ preferred_object_store_id: str | None = PreferredObjectStoreIdField
+ preferred_intermediate_object_store_id: str | None = PreferredIntermediateObjectStoreIdField
+ preferred_outputs_object_store_id: str | None = PreferredOutputsObjectStoreIdField
parameters_normalized: Literal[True] = Field(
True,
title=STEP_PARAMETERS_NORMALIZED_TITLE,
description=STEP_PARAMETERS_NORMALIZED_DESCRIPTION,
)
- parameters: Optional[dict[str, Any]] = Field(
+ parameters: dict[str, Any] | None = Field(
None,
title=STEP_PARAMETERS_TITLE,
description=f"{STEP_PARAMETERS_DESCRIPTION} If these are set, the workflow was not executed in a best-practice fashion and we the resulting invocation request may not fully reflect the executed workflow state.",
@@ -745,7 +740,7 @@ class InvocationSerializationView(str, Enum):
class InvocationSerializationParams(BaseModel):
"""Contains common parameters for customizing model serialization."""
- view: Optional[InvocationSerializationView] = Field(
+ view: InvocationSerializationView | None = Field(
default=None,
title="View",
description=(
diff --git a/lib/galaxy/schema/item_tags.py b/lib/galaxy/schema/item_tags.py
index bdf5f9948fb..a348f1d8564 100644
--- a/lib/galaxy/schema/item_tags.py
+++ b/lib/galaxy/schema/item_tags.py
@@ -1,7 +1,3 @@
-from typing import (
- Optional,
-)
-
from pydantic import (
Field,
RootModel,
@@ -26,7 +22,7 @@ class ItemTagsResponse(Model):
...,
title="name of the item tag",
)
- user_value: Optional[str] = Field(
+ user_value: str | None = Field(
None,
title="value of the item tag",
)
@@ -41,7 +37,7 @@ class ItemTagsListResponse(RootModel):
class ItemTagsCreatePayload(Model):
"""Payload schema for creating an item tag."""
- value: Optional[str] = Field(
+ value: str | None = Field(
None,
title="value of the item tag",
)
diff --git a/lib/galaxy/schema/jobs.py b/lib/galaxy/schema/jobs.py
index a1f76797049..96d1f0f5a7b 100644
--- a/lib/galaxy/schema/jobs.py
+++ b/lib/galaxy/schema/jobs.py
@@ -2,8 +2,6 @@ import json
from typing import (
Any,
Literal,
- Optional,
- Union,
)
from pydantic import (
@@ -98,12 +96,12 @@ class ReportJobErrorPayload(Model):
title="History Dataset Association ID",
description="The History Dataset Association ID related to the error.",
)
- email: Optional[str] = Field(
+ email: str | None = Field(
default=None,
title="Email",
description="Email address for communication with the user. Only required for anonymous users.",
)
- message: Optional[str] = Field(
+ message: str | None = Field(
default=None,
title="Message",
description="The optional message sent with the error report.",
@@ -121,12 +119,12 @@ class SearchJobsPayload(Model):
title="Inputs",
description="The inputs of the job.",
)
- state: Optional[JobState] = Field(
+ state: JobState | None = Field(
default=None,
title="State",
description="Current state of the job.",
)
- history_id: Union[DecodedDatabaseIdField, None] = Field(
+ history_id: DecodedDatabaseIdField | None = Field(
default=None,
title="History ID",
description="The encoded ID of the history associated with this job.",
@@ -142,7 +140,7 @@ class SearchJobsPayload(Model):
class DeleteJobPayload(Model):
- message: Optional[str] = Field(
+ message: str | None = Field(
default=None,
title="Job message",
description="Stop message",
@@ -163,7 +161,7 @@ class EncodedHdcaSourceId(SrcItem):
class EncodedDatasetJobInfo(EncodedDataItemSourceId):
- uuid: Optional[UUID4] = Field(
+ uuid: UUID4 | None = Field(
default=None,
# TODO: also deprecate on python side, https://github.com/pydantic/pydantic/issues/2255
json_schema_extra={"deprecated": True},
@@ -173,7 +171,7 @@ class EncodedDatasetJobInfo(EncodedDataItemSourceId):
class EncodedJobDetails(JobSummary):
- command_version: Optional[str] = Field(
+ command_version: str | None = Field(
default=None,
title="Command Version",
description="Tool version indicated during job execution.",
@@ -196,7 +194,7 @@ class EncodedJobDetails(JobSummary):
title="Outputs",
description="Dictionary mapping all the tool outputs (by name) to the corresponding data references.",
)
- copied_from_job_id: Optional[EncodedDatabaseIdField] = Field(
+ copied_from_job_id: EncodedDatabaseIdField | None = Field(
default=None,
title="Copied from Job-ID",
description="Reference to cached job if job execution was cached.",
@@ -206,18 +204,18 @@ class EncodedJobDetails(JobSummary):
title="Output collections",
description="",
)
- user_id: Optional[EncodedDatabaseIdField] = Field(default=None, description="User ID of user that ran this job")
+ user_id: EncodedDatabaseIdField | None = Field(default=None, description="User ID of user that ran this job")
class JobDestinationParams(Model):
- runner: Optional[str] = Field(None, title="Runner", description="Job runner class", alias="Runner")
- runner_job_id: Optional[str] = Field(
+ runner: str | None = Field(None, title="Runner", description="Job runner class", alias="Runner")
+ runner_job_id: str | None = Field(
None,
title="Runner Job ID",
description="ID assigned to submitted job by external job running system",
alias="Runner Job ID",
)
- handler: Optional[str] = Field(
+ handler: str | None = Field(
None, title="Handler", description="Name of the process that handled the job.", alias="Handler"
)
model_config = ConfigDict(extra="allow") # JobDestinationParams can have extra fields
@@ -229,9 +227,9 @@ class JobOutput(Model):
class JobConsoleOutput(Model):
- state: Optional[JobState] = Field(None, title="Job State", description="The current job's state")
- stdout: Optional[str] = Field(None, title="STDOUT", description="Tool STDOUT from job.")
- stderr: Optional[str] = Field(None, title="STDERR", description="Tool STDERR from job.")
+ state: JobState | None = Field(None, title="Job State", description="The current job's state")
+ stdout: str | None = Field(None, title="STDOUT", description="Tool STDOUT from job.")
+ stderr: str | None = Field(None, title="STDERR", description="Tool STDERR from job.")
class JobParameter(Model):
@@ -245,10 +243,10 @@ class JobParameter(Model):
title="Depth",
description="The depth of the job parameter.",
)
- value: Optional[Union[list[Optional[EncodedJobParameterHistoryItem]], float, int, bool, str]] = Field(
+ value: list[EncodedJobParameterHistoryItem | None] | float | int | bool | str | None = Field(
default=None, title="Value", description="The values of the job parameter", union_mode="left_to_right"
)
- notes: Optional[str] = Field(default=None, title="Notes", description="Notes associated with the job parameter.")
+ notes: str | None = Field(default=None, title="Notes", description="Notes associated with the job parameter.")
class JobDisplayParametersSummary(Model):
diff --git a/lib/galaxy/schema/library_contents.py b/lib/galaxy/schema/library_contents.py
index 66b3593cf98..c48dc76c69f 100644
--- a/lib/galaxy/schema/library_contents.py
+++ b/lib/galaxy/schema/library_contents.py
@@ -4,8 +4,6 @@ from typing import (
Annotated,
Any,
Literal,
- Optional,
- Union,
)
from pydantic import (
@@ -67,11 +65,11 @@ class LibraryContentsCreatePayload(Model):
[],
description="create the given list of tags on datasets",
)
- from_hda_id: Optional[DecodedDatabaseIdField] = Field(
+ from_hda_id: DecodedDatabaseIdField | None = Field(
None,
description="(only if create_type is 'file') the encoded id of an accessible HDA to copy into the library",
)
- from_hdca_id: Optional[DecodedDatabaseIdField] = Field(
+ from_hdca_id: DecodedDatabaseIdField | None = Field(
None,
description="(only if create_type is 'file') the encoded id of an accessible HDCA to copy into the library",
)
@@ -79,7 +77,7 @@ class LibraryContentsCreatePayload(Model):
"",
description="the new message attribute of the LDDA created",
)
- extended_metadata: Optional[dict[str, Any]] = Field(
+ extended_metadata: dict[str, Any] | None = Field(
None,
description="sub-dictionary containing any extended metadata to associate with the item",
)
@@ -93,7 +91,7 @@ class LibraryContentsCreatePayload(Model):
class LibraryContentsFileCreatePayload(LibraryContentsCreatePayload):
- dbkey: Union[str, list] = Field(
+ dbkey: str | list = Field(
"?",
title="database key",
)
@@ -101,7 +99,7 @@ class LibraryContentsFileCreatePayload(LibraryContentsCreatePayload):
"",
title="user selected roles",
)
- file_type: Optional[str] = Field(
+ file_type: str | None = Field(
None,
title="file type",
)
@@ -123,11 +121,11 @@ class LibraryContentsFileCreatePayload(LibraryContentsCreatePayload):
description="(only when upload_option is 'upload_directory' or 'upload_paths')."
"Setting to 'link_to_files' symlinks instead of copying the files",
)
- uuid: Optional[str] = Field(
+ uuid: str | None = Field(
None,
title="UUID of the dataset to upload",
)
- upload_files: Optional[list[dict[str, Any]]] = Field(
+ upload_files: list[dict[str, Any]] | None = Field(
None,
title="list of the uploaded files",
)
@@ -156,7 +154,7 @@ class LibraryContentsCollectionCreatePayload(LibraryContentsCreatePayload):
...,
title="list of dictionaries containing the element identifiers for the collection",
)
- name: Optional[str] = Field(
+ name: str | None = Field(
None,
title="the name of the collection",
)
@@ -171,7 +169,7 @@ class LibraryContentsCollectionCreatePayload(LibraryContentsCreatePayload):
class LibraryContentsUpdatePayload(Model):
- converted_dataset_id: Optional[DecodedDatabaseIdField] = Field(
+ converted_dataset_id: DecodedDatabaseIdField | None = Field(
None,
title="the decoded id of the dataset",
)
@@ -199,12 +197,12 @@ class LibraryContentsIndexDatasetResponse(LibraryContentsIndexResponse):
class LibraryContentsIndexListResponse(RootModel):
- root: list[Union[LibraryContentsIndexFolderResponse, LibraryContentsIndexDatasetResponse]]
+ root: list[LibraryContentsIndexFolderResponse | LibraryContentsIndexDatasetResponse]
class LibraryContentsShowResponse(Model):
name: str
- genome_build: Optional[str]
+ genome_build: str | None
update_time: str
parent_library_id: EncodedDatabaseIdField
@@ -212,7 +210,7 @@ class LibraryContentsShowResponse(Model):
class LibraryContentsShowFolderResponse(LibraryContentsShowResponse):
model_class: Annotated[Literal["LibraryFolder"], ModelClassField(Literal["LibraryFolder"])]
id: EncodedLibraryFolderDatabaseIdField
- parent_id: Optional[EncodedLibraryFolderDatabaseIdField]
+ parent_id: EncodedLibraryFolderDatabaseIdField | None
description: str
item_count: int
deleted: bool
@@ -226,16 +224,16 @@ class LibraryContentsShowDatasetResponse(LibraryContentsShowResponse):
folder_id: EncodedLibraryFolderDatabaseIdField
state: str
file_name: str
- created_from_basename: Optional[str]
- uploaded_by: Optional[str]
- message: Optional[str]
+ created_from_basename: str | None
+ uploaded_by: str | None
+ message: str | None
date_uploaded: str
file_size: int
file_ext: str
data_type: str
- misc_info: Optional[str]
- misc_blurb: Optional[str]
- peek: Optional[str]
+ misc_info: str | None
+ misc_blurb: str | None
+ peek: str | None
uuid: str
tags: TagCollection
@@ -284,9 +282,9 @@ class LibraryContentsCreateDatasetResponse(Model):
file_ext: str
data_type: str
genome_build: str
- misc_info: Optional[str]
- misc_blurb: Optional[str]
- created_from_basename: Optional[str]
+ misc_info: str | None
+ misc_blurb: str | None
+ created_from_basename: str | None
uuid: str
parent_library_id: str
@@ -307,18 +305,15 @@ class LibraryContentsPurgedResponse(LibraryContentsDeleteResponse):
purged: bool
-AnyLibraryContentsShowResponse = Union[
- LibraryContentsShowFolderResponse,
- LibraryContentsShowDatasetResponse,
-]
+AnyLibraryContentsShowResponse = LibraryContentsShowFolderResponse | LibraryContentsShowDatasetResponse
-AnyLibraryContentsCreatePayload = Union[
- LibraryContentsFolderCreatePayload, LibraryContentsFileCreatePayload, LibraryContentsCollectionCreatePayload
-]
+AnyLibraryContentsCreatePayload = (
+ LibraryContentsFolderCreatePayload | LibraryContentsFileCreatePayload | LibraryContentsCollectionCreatePayload
+)
-AnyLibraryContentsCreateResponse = Union[
- LibraryContentsCreateFolderListResponse,
- LibraryContentsCreateFileListResponse,
- LibraryContentsCreateDatasetCollectionResponse,
- LibraryContentsCreateDatasetResponse,
-]
+AnyLibraryContentsCreateResponse = (
+ LibraryContentsCreateFolderListResponse
+ | LibraryContentsCreateFileListResponse
+ | LibraryContentsCreateDatasetCollectionResponse
+ | LibraryContentsCreateDatasetResponse
+)
diff --git a/lib/galaxy/schema/notifications.py b/lib/galaxy/schema/notifications.py
index 29ec3b36f8b..f8e1b0a558e 100644
--- a/lib/galaxy/schema/notifications.py
+++ b/lib/galaxy/schema/notifications.py
@@ -5,7 +5,6 @@ from typing import (
Any,
Generic,
Literal,
- Optional,
Union,
)
@@ -67,7 +66,7 @@ class PersonalNotificationCategory(str, Enum):
# workflow_execution_completed = "workflow_execution_completed"
-NotificationCategory = Union[MandatoryNotificationCategory, PersonalNotificationCategory]
+NotificationCategory = MandatoryNotificationCategory | PersonalNotificationCategory
class MessageNotificationContentBase(Model):
@@ -90,7 +89,7 @@ class ActionLink(Model):
class BroadcastNotificationContent(MessageNotificationContentBase):
category: Literal[MandatoryNotificationCategory.broadcast] = MandatoryNotificationCategory.broadcast
- action_links: Optional[list[ActionLink]] = Field(
+ action_links: list[ActionLink] | None = Field(
None,
title="Action links",
description="The optional action links (buttons) to be displayed in the notification.",
@@ -146,19 +145,12 @@ NotificationContentField = Field(
)
AnyUserNotificationContent = Annotated[
- Union[
- MessageNotificationContent,
- NewSharedItemNotificationContent,
- StorageOperationNotificationContent,
- ],
+ MessageNotificationContent | NewSharedItemNotificationContent | StorageOperationNotificationContent,
NotificationContentField,
]
AnyNotificationContent = Annotated[
- Union[
- AnyUserNotificationContent,
- BroadcastNotificationContent,
- ],
+ AnyUserNotificationContent | BroadcastNotificationContent,
NotificationContentField,
]
@@ -222,7 +214,7 @@ class NotificationResponse(Model):
create_time: datetime = NotificationCreateTimeField
update_time: datetime = NotificationUpdateTimeField
publication_time: datetime = NotificationPublicationTimeField
- expiration_time: Optional[datetime] = NotificationExpirationTimeField
+ expiration_time: datetime | None = NotificationExpirationTimeField
content: AnyNotificationContent
model_config = ConfigDict(from_attributes=True)
@@ -232,7 +224,7 @@ class UserNotificationResponse(NotificationResponse):
category: PersonalNotificationCategory = NotificationCategoryField
content: AnyUserNotificationContent
- seen_time: Optional[datetime] = Field(
+ seen_time: datetime | None = Field(
None,
title="Seen time",
description="The time when the notification was seen by the user. If not set, the notification was not seen yet.",
@@ -284,12 +276,12 @@ class NotificationCreateData(Model):
category: NotificationCategory = NotificationCategoryField
variant: NotificationVariant = NotificationVariantField
content: AnyNotificationContent
- publication_time: Optional[OffsetNaiveDatetime] = Field(
+ publication_time: OffsetNaiveDatetime | None = Field(
None,
title="Publication time",
description="The time when the notification should be published. Notifications can be created and then scheduled to be published at a later time.",
)
- expiration_time: Optional[OffsetNaiveDatetime] = Field(
+ expiration_time: OffsetNaiveDatetime | None = Field(
None,
title="Expiration time",
description="The time when the notification should expire. By default it will expire after 6 months. Expired notifications will be permanently deleted.",
@@ -332,7 +324,7 @@ class GenericNotificationCreate(GenericModel, Generic[DatabaseIdT]):
class NotificationCreateRequest(GenericNotificationCreate[int]):
- galaxy_url: Optional[str] = Field(
+ galaxy_url: str | None = Field(
None,
title="Galaxy URL",
description="The URL of the Galaxy instance. Used to generate links in the notification content.",
@@ -378,12 +370,12 @@ class NotificationUpdateRequest(Model):
class UserNotificationUpdateRequest(NotificationUpdateRequest):
"""A notification update request specific to the user."""
- seen: Optional[bool] = Field(
+ seen: bool | None = Field(
None,
title="Seen",
description="Whether the notification should be marked as seen by the user. If not set, the notification will not be changed.",
)
- deleted: Optional[bool] = Field(
+ deleted: bool | None = Field(
None,
title="Deleted",
description="Whether the notification should be marked as deleted by the user. If not set, the notification will not be changed.",
@@ -393,27 +385,27 @@ class UserNotificationUpdateRequest(NotificationUpdateRequest):
class NotificationBroadcastUpdateRequest(NotificationUpdateRequest):
"""A notification update request specific for broadcasting."""
- source: Optional[str] = Field(
+ source: str | None = Field(
None,
title="Source",
description="The source of the notification. Represents the agent that created the notification.",
)
- variant: Optional[NotificationVariant] = Field(
+ variant: NotificationVariant | None = Field(
None,
title="Variant",
description="The variant of the notification. Used to express the importance of the notification.",
)
- publication_time: Optional[OffsetNaiveDatetime] = Field(
+ publication_time: OffsetNaiveDatetime | None = Field(
None,
title="Publication time",
description="The time when the notification should be published. Notifications can be created and then scheduled to be published at a later time.",
)
- expiration_time: Optional[OffsetNaiveDatetime] = Field(
+ expiration_time: OffsetNaiveDatetime | None = Field(
None,
title="Expiration time",
description="The time when the notification should expire. By default it will expire after 6 months. Expired notifications will be permanently deleted.",
)
- content: Optional[BroadcastNotificationContent] = Field(
+ content: BroadcastNotificationContent | None = Field(
None,
title="Content",
description="The content of the broadcast notification. Broadcast notifications are displayed prominently to all users and can contain action links to redirect the user to a specific page.",
diff --git a/lib/galaxy/schema/remote_files.py b/lib/galaxy/schema/remote_files.py
index f49300f9d31..6c7a505954a 100644
--- a/lib/galaxy/schema/remote_files.py
+++ b/lib/galaxy/schema/remote_files.py
@@ -3,8 +3,6 @@ from typing import (
Annotated,
Any,
Literal,
- Optional,
- Union,
)
from pydantic import (
@@ -58,7 +56,7 @@ class FilesSourcePlugin(Model):
description="The display label for this plugin.",
examples=["Library Import Directory"],
)
- doc: Optional[str] = Field(
+ doc: str | None = Field(
None,
title="Documentation",
description="Documentation or extended description for this plugin.",
@@ -75,17 +73,17 @@ class FilesSourcePlugin(Model):
description="Whether this files source plugin allows write access.",
examples=[False],
)
- requires_roles: Optional[str] = Field(
+ requires_roles: str | None = Field(
None,
title="Requires roles",
description="Only users with the roles specified here can access this files source.",
)
- requires_groups: Optional[str] = Field(
+ requires_groups: str | None = Field(
None,
title="Requires groups",
description="Only users belonging to the groups specified here can access this files source.",
)
- url: Optional[str] = Field(
+ url: str | None = Field(
None,
title="URL",
description="Optional URL that might be provided by some plugins to link to the remote source.",
@@ -107,7 +105,7 @@ class BrowsableFilesSourcePlugin(FilesSourcePlugin):
class FilesSourcePluginList(RootModel):
- root: list[Union[BrowsableFilesSourcePlugin, FilesSourcePlugin]] = Field(
+ root: list[BrowsableFilesSourcePlugin | FilesSourcePlugin] = Field(
default=[],
title="List of files source plugins",
examples=[
@@ -143,7 +141,7 @@ class RemoteFile(RemoteEntry):
class_: Literal["File"] = Field(..., alias="class")
size: int = Field(..., title="Size", description="The size of the file in bytes.")
ctime: str = Field(..., title="Creation time", description="The creation time of the file.")
- hashes: Optional[list[RemoteFileHash]] = Field(
+ hashes: list[RemoteFileHash] | None = Field(
None, title="Hashes", description="List of precomputed hashes for the file, if available."
)
@@ -159,7 +157,7 @@ class ListJstreeResponse(RootModel):
AnyRemoteEntry = Annotated[
- Union[RemoteFile, RemoteDirectory],
+ RemoteFile | RemoteDirectory,
Field(discriminator="class_"),
]
@@ -172,7 +170,7 @@ class ListUriResponse(RootModel):
)
-AnyRemoteFilesListResponse = Union[ListUriResponse, ListJstreeResponse]
+AnyRemoteFilesListResponse = ListUriResponse | ListJstreeResponse
class CreateEntryPayload(Model):
@@ -202,7 +200,7 @@ class CreatedEntryResponse(Model):
description="The URI of the created entry.",
examples=["gxfiles://my_new_entry"],
)
- external_link: Optional[str] = Field(
+ external_link: str | None = Field(
default=None,
title="External link",
description="An optional external link to the created entry if available.",
diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py
index 6744396868f..f9ff8e38cd4 100644
--- a/lib/galaxy/schema/schema.py
+++ b/lib/galaxy/schema/schema.py
@@ -12,7 +12,6 @@ from typing import (
Literal,
Optional,
TypeAlias,
- Union,
)
from uuid import UUID
@@ -78,7 +77,7 @@ INVOCATION_STEP_MODEL_CLASS = Literal["WorkflowInvocationStep"]
INVOCATION_REPORT_MODEL_CLASS = Literal["Report"]
IMPLICIT_COLLECTION_JOBS_MODEL_CLASS = Literal["ImplicitCollectionJobs"]
-OptionalNumberT = Optional[Union[int, float]]
+OptionalNumberT = int | float | None
TAG_ITEM_PATTERN = r"^([^\s.:])+(\.[^\s.:]+)*(:\S+)?$"
@@ -179,7 +178,7 @@ DownloadUrlField: RelativeUrl = Field(
description="The URL to download this item from the server.",
)
-AnnotationField: Optional[str] = Field(
+AnnotationField: str | None = Field(
...,
title="Annotation",
description="An annotation to provide details or to help understand the purpose and usage of this item.",
@@ -244,14 +243,14 @@ PopulatedStateField: DatasetCollectionPopulatedState = Field(
),
)
-PopulatedStateMessageField: Optional[str] = Field(
+PopulatedStateMessageField: str | None = Field(
None,
title="Populated State Message",
description="Optional message with further information in case the population of the dataset collection failed.",
)
ElementCountField = Annotated[
- Optional[int],
+ int | None,
Field(
None,
title="Element Count",
@@ -263,7 +262,7 @@ ElementCountField = Annotated[
]
PopulatedField = Annotated[
- Optional[bool],
+ bool | None,
Field(
title="Populated",
description="Whether the dataset collection elements (and any subcollections elements) were successfully populated.",
@@ -285,7 +284,7 @@ UuidField = Annotated[
),
]
-GenomeBuildField: Optional[str] = Field(
+GenomeBuildField: str | None = Field(
"?",
title="Genome Build",
description="TODO",
@@ -324,7 +323,7 @@ NiceTotalDiskUsageField = Field(
title="Nice total disc usage",
description="Size of all non-purged, unique datasets of the user in a nice format.",
)
-FlexibleUserIdType = Union[DecodedDatabaseIdField, Literal["current"]]
+FlexibleUserIdType = DecodedDatabaseIdField | Literal["current"]
class Model(BaseModel):
@@ -370,18 +369,18 @@ class UserModel(BaseUserModel, WithModelClass):
active: bool = Field(title="Active", description="User is active")
model_class: USER_MODEL_CLASS = ModelClassField(USER_MODEL_CLASS)
- last_password_change: Optional[datetime] = Field(title="Last password change", description="")
+ last_password_change: datetime | None = Field(title="Last password change", description="")
class LimitedUserModel(Model):
"""This is used when config options (expose_user_name and expose_user_email) are in place."""
id: UserId
- username: Optional[str] = None
- email: Optional[str] = None
+ username: str | None = None
+ email: str | None = None
-MaybeLimitedUserModel = Union[UserModel, LimitedUserModel]
+MaybeLimitedUserModel = UserModel | LimitedUserModel
class DiskUsageUserModel(Model):
@@ -390,28 +389,28 @@ class DiskUsageUserModel(Model):
class CreatedUserModel(UserModel, DiskUsageUserModel):
- preferred_object_store_id: Optional[str] = PreferredObjectStoreIdField
+ preferred_object_store_id: str | None = PreferredObjectStoreIdField
class AnonUserModel(DiskUsageUserModel):
- quota_percent: Optional[float] = QuotaPercentField
+ quota_percent: float | None = QuotaPercentField
class DetailedUserModel(BaseUserModel, AnonUserModel):
is_admin: bool = Field(default=..., title="Is admin", description="User is admin")
purged: bool = Field(default=..., title="Purged", description="User is purged")
preferences: dict[Any, Any] = Field(default=..., title="Preferences", description="Preferences of the user")
- preferred_object_store_id: Optional[str] = PreferredObjectStoreIdField
+ preferred_object_store_id: str | None = PreferredObjectStoreIdField
quota: str = Field(default=..., title="Quota", description="Quota applicable to the user")
- quota_bytes: Optional[int] = Field(
+ quota_bytes: int | None = Field(
default=None, title="Quota in bytes", description="Quota applicable to the user in bytes."
)
class UserUpdatePayload(Model):
- active: Annotated[Optional[bool], Field(title="Active", description="User is active")] = None
- username: Annotated[Optional[str], Field(title="Username", description="The name of the user.")] = None
- preferred_object_store_id: Annotated[Optional[str], PreferredObjectStoreIdField]
+ active: Annotated[bool | None, Field(title="Active", description="User is active")] = None
+ username: Annotated[str | None, Field(title="Username", description="The name of the user.")] = None
+ preferred_object_store_id: Annotated[str | None, PreferredObjectStoreIdField]
class UserCreationPayload(Model):
@@ -529,11 +528,11 @@ class CustomBuildCreationPayload(CustomBuildBaseModel):
class CreatedCustomBuild(CustomBuildBaseModel):
len: EncodedDatabaseIdField = Field(default=..., title="Length", description="The primary id of the len file.")
- count: Optional[str] = Field(default=None, title="Count", description="The number of chromosomes/contigs.")
- fasta: Optional[EncodedDatabaseIdField] = Field(
+ count: str | None = Field(default=None, title="Count", description="The number of chromosomes/contigs.")
+ fasta: EncodedDatabaseIdField | None = Field(
default=None, title="Fasta", description="The primary id of the fasta file from a history."
)
- linecount: Optional[EncodedDatabaseIdField] = Field(
+ linecount: EncodedDatabaseIdField | None = Field(
default=None, title="Line count", description="The primary id of a linecount dataset."
)
@@ -703,7 +702,7 @@ class HistoryItemBase(Model):
"""Basic information provided by items contained in a History."""
id: EncodedDatabaseIdField
- name: Optional[str] = Field(
+ name: str | None = Field(
title="Name",
description="The name of the item.",
)
@@ -728,7 +727,7 @@ class HistoryItemBase(Model):
class HistoryItemCommon(HistoryItemBase):
"""Common information provided by items contained in a History."""
- type_id: Optional[str] = Field(
+ type_id: str | None = Field(
default=None,
title="Type - ID",
description="The type and the encoded ID of this item. Used for caching.",
@@ -740,7 +739,7 @@ class HistoryItemCommon(HistoryItemBase):
description="The type of this item.",
)
create_time: datetime = CreateTimeField
- update_time: Optional[datetime] = UpdateTimeField
+ update_time: datetime | None = UpdateTimeField
url: RelativeUrlField
tags: TagCollection
@@ -753,7 +752,7 @@ class HDACommon(HistoryItemCommon):
description="This is always `dataset` for datasets.",
),
]
- copied_from_ldda_id: Optional[EncodedDatabaseIdField] = None
+ copied_from_ldda_id: EncodedDatabaseIdField | None = None
class HDASummary(HDACommon):
@@ -765,7 +764,7 @@ class HDASummary(HDACommon):
description="The encoded ID of the dataset associated with this item.",
)
state: DatasetStateField
- extension: Optional[str] = Field(
+ extension: str | None = Field(
...,
title="Extension",
description="The extension of the dataset.",
@@ -776,8 +775,8 @@ class HDASummary(HDACommon):
title="Purged",
description="Whether this dataset has been removed from disk.",
)
- genome_build: Optional[str] = GenomeBuildField
- object_store_id: Optional[str] = Field(
+ genome_build: str | None = GenomeBuildField
+ object_store_id: str | None = Field(
None,
title="Object Store ID",
description="The ID of the object store that this dataset is stored in.",
@@ -821,7 +820,7 @@ class DatasetHash(Model):
title="Hash Value",
description="The hash value.",
)
- extra_files_path: Optional[str] = Field(
+ extra_files_path: str | None = Field(
None,
title="Extra Files Path",
description="The path to the extra files used to generate the hash.",
@@ -839,7 +838,7 @@ DatasetSourceTransformActionField: DatasetSourceTransformActionType = Field(
title="Action",
description="Action that was applied to dataset source content to transform it into the dataset",
)
-DatasetSourceTransformActionDatatypeExtField: Optional[str] = Field(
+DatasetSourceTransformActionDatatypeExtField: str | None = Field(
None,
title="Datatype Extension",
description="If action is 'datatype_groom', this is the datatype that was used to find and run the grooming code as part of the transform action.",
@@ -848,7 +847,7 @@ DatasetSourceTransformActionDatatypeExtField: Optional[str] = Field(
class DatasetSourceTransform(Model):
action: DatasetSourceTransformActionType = DatasetSourceTransformActionField
- datatype_ext: Optional[str] = DatasetSourceTransformActionDatatypeExtField
+ datatype_ext: str | None = DatasetSourceTransformActionDatatypeExtField
class DatasetSource(Model):
@@ -859,10 +858,10 @@ class DatasetSource(Model):
)
source_uri: Annotated[RelativeUrl, Field(..., title="Source URI", description="The URI of the dataset source.")]
extra_files_path: Annotated[
- Optional[str], Field(title="Extra Files Path", description="The path to the extra files.")
+ str | None, Field(title="Extra Files Path", description="The path to the extra files.")
] = None
transform: Annotated[
- Optional[list[DatasetSourceTransform]],
+ list[DatasetSourceTransform] | None,
Field(
title="Transform",
description="The transformations applied to the dataset source.",
@@ -876,12 +875,12 @@ class HDADetailed(HDASummary, WithModelClass):
model_class: Annotated[HDA_MODEL_CLASS, ModelClassField(HDA_MODEL_CLASS)]
hda_ldda: DatasetSourceType = HdaLddaField
accessible: bool = AccessibleField
- misc_info: Optional[str] = Field(
+ misc_info: str | None = Field(
default=None,
title="Miscellaneous Information",
description="TODO",
)
- misc_blurb: Optional[str] = Field(
+ misc_blurb: str | None = Field(
default=None,
title="Miscellaneous Blurb",
description="TODO",
@@ -901,7 +900,7 @@ class HDADetailed(HDASummary, WithModelClass):
title="Resubmitted",
description="Whether the job creating this dataset has been resubmitted.",
)
- metadata: Optional[Any] = Field( # TODO: create pydantic model for metadata?
+ metadata: Any | None = Field( # TODO: create pydantic model for metadata?
default=None,
title="Metadata",
description="The metadata associated with this dataset.",
@@ -917,7 +916,7 @@ class HDADetailed(HDASummary, WithModelClass):
description="The fully qualified name of the class implementing the data type of this dataset.",
examples=["galaxy.datatypes.data.Text"],
)
- peek: Optional[str] = Field(
+ peek: str | None = Field(
default=None,
title="Peek",
description="A few lines of contents from the start of the file.",
@@ -938,7 +937,7 @@ class HDADetailed(HDASummary, WithModelClass):
title="Permissions",
description="Role-based access and manage control permissions for the dataset.",
)
- file_name: Optional[str] = Field(
+ file_name: str | None = Field(
default=None,
title="File Name",
description="The full path to the dataset file.",
@@ -960,12 +959,12 @@ class HDADetailed(HDASummary, WithModelClass):
title="Validated State",
description="The state of the datatype validation for this dataset.",
)
- validated_state_message: Optional[str] = Field(
+ validated_state_message: str | None = Field(
None,
title="Validated State Message",
description="The message with details about the datatype validation result for this dataset.",
)
- annotation: Optional[str] = AnnotationField
+ annotation: str | None = AnnotationField
download_url: RelativeUrl = DownloadUrlField
type: Annotated[
Literal["file"],
@@ -984,7 +983,7 @@ class HDADetailed(HDASummary, WithModelClass):
}, # TODO: Should this field be deprecated as announced in release 16.04?
),
] = "file"
- created_from_basename: Optional[str] = Field(
+ created_from_basename: str | None = Field(
None,
title="Created from basename",
description="The basename of the output that produced this dataset.", # TODO: is that correct?
@@ -1014,10 +1013,10 @@ class HDADetailed(HDASummary, WithModelClass):
),
]
copied_from_history_dataset_association_id: Annotated[
- Optional[EncodedDatabaseIdField], Field(description="ID of HDA this HDA was copied from.")
+ EncodedDatabaseIdField | None, Field(description="ID of HDA this HDA was copied from.")
] = None
copied_from_library_dataset_dataset_association_id: Annotated[
- Optional[EncodedDatabaseIdField], Field(description="ID of LDDA this HDA was copied from.")
+ EncodedDatabaseIdField | None, Field(description="ID of LDDA this HDA was copied from.")
] = None
@@ -1029,12 +1028,12 @@ class HDAExtended(HDADetailed):
title="Tool Version",
description="The version of the tool that produced this dataset.",
)
- parent_id: Optional[DecodedDatabaseIdField] = Field(
+ parent_id: DecodedDatabaseIdField | None = Field(
None,
title="Parent ID",
description="TODO",
)
- designation: Optional[str] = Field(
+ designation: str | None = Field(
None,
title="Designation",
description="TODO",
@@ -1050,7 +1049,7 @@ class DCSummary(Model, WithModelClass):
update_time: datetime = UpdateTimeField
collection_type: CollectionType = CollectionTypeField
populated_state: DatasetCollectionPopulatedState = PopulatedStateField
- populated_state_message: Optional[str] = PopulatedStateMessageField
+ populated_state_message: str | None = PopulatedStateMessageField
element_count: ElementCountField
@@ -1065,8 +1064,8 @@ class HDAObject(Model, WithModelClass):
hda_ldda: DatasetSourceType = HdaLddaField
history_id: HistoryID
tags: list[str]
- copied_from_ldda_id: Optional[EncodedDatabaseIdField] = None
- accessible: Optional[bool] = None
+ copied_from_ldda_id: EncodedDatabaseIdField | None = None
+ accessible: bool | None = None
purged: bool
model_config = ConfigDict(extra="allow")
@@ -1079,7 +1078,7 @@ class DCObject(Model, WithModelClass):
collection_type: CollectionType = CollectionTypeField
populated: PopulatedField = None
element_count: ElementCountField
- contents_url: Optional[ContentsUrlField] = None
+ contents_url: ContentsUrlField | None = None
elements: list["DCESummary"] = ElementsField
elements_states: ElementsStatesDict = Field(
..., description="A dictionary containing counts for each dataset state in the collection."
@@ -1092,7 +1091,7 @@ class DCObject(Model, WithModelClass):
elements_datatypes: set[str] = Field(
..., description="A set containing all the different element datatypes in the collection."
)
- column_definitions: Optional[SampleSheetColumnDefinitions] = Field(
+ column_definitions: SampleSheetColumnDefinitions | None = Field(
None, description="Column definitions for sample sheet collections."
)
@@ -1112,17 +1111,17 @@ class DCESummary(Model, WithModelClass):
title="Element Identifier",
description="The actual name of this element.",
)
- element_type: Optional[DCEType] = Field(
+ element_type: DCEType | None = Field(
None,
title="Element Type",
description="The type of the element. Used to interpret the `object` field.",
)
- object: Optional[Union[HDAObject, HDADetailed, DCObject]] = Field(
+ object: HDAObject | HDADetailed | DCObject | None = Field(
None,
title="Object",
description="The element's specific data depending on the value of `element_type`.",
)
- columns: Optional[SampleSheetRow] = Field(
+ columns: SampleSheetRow | None = Field(
None,
title="Columns",
description="A row (or list of columns) of data associated with this element",
@@ -1253,7 +1252,7 @@ class HDCASummary(HDCACommon, WithModelClass):
collection_type: CollectionType = CollectionTypeField
populated_state: DatasetCollectionPopulatedState = PopulatedStateField
- populated_state_message: Optional[str] = PopulatedStateMessageField
+ populated_state_message: str | None = PopulatedStateMessageField
element_count: ElementCountField
elements_datatypes: set[str] = Field(
..., description="A set containing all the different element datatypes in the collection."
@@ -1266,24 +1265,24 @@ class HDCASummary(HDCACommon, WithModelClass):
title="Datasets deleted",
description="The number of elements in the collection that are marked as deleted.",
)
- job_source_id: Optional[EncodedDatabaseIdField] = Field(
+ job_source_id: EncodedDatabaseIdField | None = Field(
None,
title="Job Source ID",
description="The encoded ID of the Job that produced this dataset collection. Used to track the state of the job.",
)
- job_source_type: Optional[JobSourceType] = Field(
+ job_source_type: JobSourceType | None = Field(
None,
title="Job Source Type",
description="The type of job (model class) that produced this dataset collection. Used to track the state of the job.",
)
- job_state_summary: Optional[HDCJobStateSummary] = Field(
+ job_state_summary: HDCJobStateSummary | None = Field(
None,
title="Job State Summary",
description="Overview of the job states working inside the dataset collection.",
)
contents_url: ContentsUrlField
collection_id: DatasetCollectionId
- store_times_summary: Optional[list[OldestCreateTimeByObjectStoreId]] = Field(
+ store_times_summary: list[OldestCreateTimeByObjectStoreId] | None = Field(
None,
title="Store Times Summary",
description=(
@@ -1299,11 +1298,11 @@ class HDCADetailed(HDCASummary):
populated: PopulatedField = None
elements: list[DCESummary] = ElementsField
- implicit_collection_jobs_id: Optional[EncodedDatabaseIdField] = Field(
+ implicit_collection_jobs_id: EncodedDatabaseIdField | None = Field(
None,
description="Encoded ID for the ICJ object describing the collection of jobs corresponding to this collection",
)
- column_definitions: Optional[SampleSheetColumnDefinitions] = Field(
+ column_definitions: SampleSheetColumnDefinitions | None = Field(
None,
description="Column data associated with each element of this collection.",
)
@@ -1379,21 +1378,17 @@ class ChangeDbkeyOperationParams(BulkOperationParams):
class TagOperationParams(BulkOperationParams):
- type: Union[Literal["add_tags"], Literal["remove_tags"]]
+ type: Literal["add_tags"] | Literal["remove_tags"]
tags: list[str]
-AnyBulkOperationParams = Union[
- ChangeDatatypeOperationParams,
- ChangeDbkeyOperationParams,
- TagOperationParams,
-]
+AnyBulkOperationParams = ChangeDatatypeOperationParams | ChangeDbkeyOperationParams | TagOperationParams
class HistoryContentBulkOperationPayload(Model):
operation: HistoryContentItemOperation
- items: Optional[list[HistoryContentItem]] = None
- params: Optional[AnyBulkOperationParams] = None
+ items: list[HistoryContentItem] | None = None
+ params: AnyBulkOperationParams | None = None
class BulkOperationItemError(Model):
@@ -1409,27 +1404,27 @@ class HistoryContentBulkOperationResult(Model):
class UpdateHistoryContentsPayload(Model):
"""Can contain arbitrary/dynamic fields that will be updated for a particular history item."""
- name: Optional[str] = Field(
+ name: str | None = Field(
None,
title="Name",
description="The new name of the item.",
)
- deleted: Optional[bool] = Field(
+ deleted: bool | None = Field(
None,
title="Deleted",
description="Whether this item is marked as deleted.",
)
- visible: Optional[bool] = Field(
+ visible: bool | None = Field(
None,
title="Visible",
description="Whether this item is visible in the history.",
)
- annotation: Optional[str] = Field(
+ annotation: str | None = Field(
None,
title="Annotation",
description="A user-defined annotation for this item.",
)
- tags: Optional[TagCollection] = Field(
+ tags: TagCollection | None = Field(
None,
title="Tags",
description="A list of tags to add to this item.",
@@ -1481,10 +1476,10 @@ class HistorySummary(Model, WithModelClass):
title="Count",
description="The number of items in the history.",
)
- annotation: Optional[str] = AnnotationField
+ annotation: str | None = AnnotationField
tags: TagCollection
update_time: datetime = UpdateTimeField
- preferred_object_store_id: Optional[str] = PreferredObjectStoreIdField
+ preferred_object_store_id: str | None = PreferredObjectStoreIdField
purge_task: Optional["AsyncTaskResultSummary"] = Field(
None,
title="Purge Task",
@@ -1516,7 +1511,7 @@ class HistoryActiveContentCounts(Model):
HistoryStateCounts = dict[DatasetState, int]
HistoryStateIds = dict[DatasetState, list[DecodedDatabaseIdField]]
-HistoryContentStates = Union[DatasetState, DatasetCollectionPopulatedState]
+HistoryContentStates = DatasetState | DatasetCollectionPopulatedState
HistoryContentStateCounts = dict[HistoryContentStates, int]
@@ -1529,7 +1524,7 @@ class HistoryDetailed(HistorySummary): # Equivalent to 'dev-detailed' view, whi
title="Size",
description="The total size of the contents of this history in bytes.",
)
- user_id: Optional[EncodedDatabaseIdField] = Field(
+ user_id: EncodedDatabaseIdField | None = Field(
None,
title="User ID",
description="The encoded ID of the user that owns this History.",
@@ -1540,22 +1535,22 @@ class HistoryDetailed(HistorySummary): # Equivalent to 'dev-detailed' view, whi
title="Importable",
description="Whether this History can be imported by other users with a shared link.",
)
- slug: Optional[str] = Field(
+ slug: str | None = Field(
None,
title="Slug",
description="Part of the URL to uniquely identify this History by link in a readable way.",
)
- username: Optional[str] = Field(
+ username: str | None = Field(
None,
title="Username",
description="Owner of the history",
)
- username_and_slug: Optional[str] = Field(
+ username_and_slug: str | None = Field(
None,
title="Username and slug",
description="The relative URL in the form of /u/{username}/h/{slug}",
)
- genome_build: Optional[str] = GenomeBuildField
+ genome_build: str | None = GenomeBuildField
state: DatasetState = Field(
...,
title="State",
@@ -1589,17 +1584,17 @@ class CustomHistoryView(HistoryDetailed):
"""
# Define a few more useful fields to be optional that are not part of HistoryDetailed
- contents_active: Optional[HistoryActiveContentCounts] = Field(
+ contents_active: HistoryActiveContentCounts | None = Field(
default=None,
title="Contents Active",
description=("Contains the number of active, deleted or hidden items in a History."),
)
- contents_states: Optional[HistoryContentStateCounts] = Field(
+ contents_states: HistoryContentStateCounts | None = Field(
default=None,
title="Contents States",
description="A dictionary keyed to possible dataset states and valued with the number of datasets in this history that have those states.",
)
- nice_size: Optional[str] = Field(
+ nice_size: str | None = Field(
default=None,
title="Nice Size",
description="The total size of the contents of this history in a human-readable format.",
@@ -1607,49 +1602,45 @@ class CustomHistoryView(HistoryDetailed):
AnyHistoryView = Annotated[
- Union[
- CustomHistoryView,
- HistoryDetailed,
- HistorySummary,
- ],
+ CustomHistoryView | HistoryDetailed | HistorySummary,
Field(union_mode="left_to_right"),
]
class UpdateHistoryPayload(Model):
- name: Optional[str] = None
- annotation: Optional[str] = None
- tags: Optional[TagCollection] = None
- published: Optional[bool] = None
- importable: Optional[bool] = None
- deleted: Optional[bool] = None
- purged: Optional[bool] = None
- genome_build: Optional[str] = None
- preferred_object_store_id: Optional[str] = None
+ name: str | None = None
+ annotation: str | None = None
+ tags: TagCollection | None = None
+ published: bool | None = None
+ importable: bool | None = None
+ deleted: bool | None = None
+ purged: bool | None = None
+ genome_build: str | None = None
+ preferred_object_store_id: str | None = None
class ExportHistoryArchivePayload(Model):
- gzip: Optional[bool] = Field(
+ gzip: bool | None = Field(
default=True,
title="GZip",
description="Whether to export as gzip archive.",
)
- include_hidden: Optional[bool] = Field(
+ include_hidden: bool | None = Field(
default=False,
title="Include Hidden",
description="Whether to include hidden datasets in the exported archive.",
)
- include_deleted: Optional[bool] = Field(
+ include_deleted: bool | None = Field(
default=False,
title="Include Deleted",
description="Whether to include deleted datasets in the exported archive.",
)
- file_name: Optional[str] = Field(
+ file_name: str | None = Field(
default=None,
title="File Name",
description="The name of the file containing the exported history.",
)
- directory_uri: Optional[str] = Field(
+ directory_uri: str | None = Field(
default=None,
title="Directory URI",
description=(
@@ -1657,7 +1648,7 @@ class ExportHistoryArchivePayload(Model):
"using the `galaxy.files` URI infrastructure."
),
)
- force: Optional[bool] = Field( # Hack to force rebuild everytime during dev
+ force: bool | None = Field( # Hack to force rebuild everytime during dev
default=None,
title="Force Rebuild",
description="Whether to force a rebuild of the history archive.",
@@ -1670,18 +1661,18 @@ WorkflowSortByEnum = Literal["create_time", "update_time", "name"]
class WorkflowIndexQueryPayload(Model):
show_deleted: bool = False
show_hidden: bool = False
- show_published: Optional[bool] = None
- show_shared: Optional[bool] = None
- sort_by: Optional[WorkflowSortByEnum] = Field(None, title="Sort By", description="Sort workflows by this attribute")
- sort_desc: Optional[bool] = Field(
+ show_published: bool | None = None
+ show_shared: bool | None = None
+ sort_by: WorkflowSortByEnum | None = Field(None, title="Sort By", description="Sort workflows by this attribute")
+ sort_desc: bool | None = Field(
None, title="Sort descending", description="Explicitly sort by descending if sort_by is specified."
)
- limit: Optional[int] = Field(
+ limit: int | None = Field(
default=None,
lt=1000,
)
- offset: Optional[int] = Field(default=0, description="Number of workflows to skip")
- search: Optional[str] = Field(default=None, title="Filter text", description="Freetext to search.")
+ offset: int | None = Field(default=0, description="Number of workflows to skip")
+ search: str | None = Field(default=None, title="Filter text", description="Freetext to search.")
skip_step_counts: bool = False
@@ -1695,20 +1686,20 @@ class JobIndexSortByEnum(str, Enum):
class JobIndexQueryPayload(Model):
- states: Optional[list[str]] = None
+ states: list[str] | None = None
user_details: bool = False
- user_id: Optional[DecodedDatabaseIdField] = None
- tool_ids: Optional[list[str]] = None
- tool_ids_like: Optional[list[str]] = None
- date_range_min: Optional[Union[OffsetNaiveDatetime, date]] = None
- date_range_max: Optional[Union[OffsetNaiveDatetime, date]] = None
- history_id: Optional[DecodedDatabaseIdField] = None
- workflow_id: Optional[DecodedDatabaseIdField] = None
- invocation_id: Optional[DecodedDatabaseIdField] = None
- implicit_collection_jobs_id: Optional[DecodedDatabaseIdField] = None
- tool_request_id: Optional[DecodedDatabaseIdField] = None
+ user_id: DecodedDatabaseIdField | None = None
+ tool_ids: list[str] | None = None
+ tool_ids_like: list[str] | None = None
+ date_range_min: OffsetNaiveDatetime | date | None = None
+ date_range_max: OffsetNaiveDatetime | date | None = None
+ history_id: DecodedDatabaseIdField | None = None
+ workflow_id: DecodedDatabaseIdField | None = None
+ invocation_id: DecodedDatabaseIdField | None = None
+ implicit_collection_jobs_id: DecodedDatabaseIdField | None = None
+ tool_request_id: DecodedDatabaseIdField | None = None
order_by: JobIndexSortByEnum = JobIndexSortByEnum.update_time
- search: Optional[str] = None
+ search: str | None = None
limit: int = 500
offset: int = 0
@@ -1720,24 +1711,22 @@ class InvocationSortByEnum(str, Enum):
class InvocationIndexQueryPayload(Model):
- workflow_id: Optional[int] = Field(
+ workflow_id: int | None = Field(
None, title="Workflow ID", description="Return only invocations for this Workflow ID"
)
- history_id: Optional[int] = Field(
- None, title="History ID", description="Return only invocations for this History ID"
- )
- job_id: Optional[int] = Field(None, title="Job ID", description="Return only invocations for this Job ID")
- user_id: Optional[int] = Field(None, title="User ID", description="Return invocations for this User ID")
- sort_by: Optional[InvocationSortByEnum] = Field(
+ history_id: int | None = Field(None, title="History ID", description="Return only invocations for this History ID")
+ job_id: int | None = Field(None, title="Job ID", description="Return only invocations for this Job ID")
+ user_id: int | None = Field(None, title="User ID", description="Return invocations for this User ID")
+ sort_by: InvocationSortByEnum | None = Field(
None, title="Sort By", description="Sort Workflow Invocations by this attribute"
)
sort_desc: bool = Field(default=False, description="Sort in descending order?")
include_terminal: bool = Field(default=True, description="Set to false to only include terminal Invocations.")
- limit: Optional[int] = Field(
+ limit: int | None = Field(
default=100,
lt=1000,
)
- offset: Optional[int] = Field(default=0, description="Number of invocations to skip")
+ offset: int | None = Field(default=0, description="Number of invocations to skip")
include_nested_invocations: bool = True
@@ -1750,54 +1739,54 @@ PageSortByEnum = Literal["create_time", "title", "update_time", "username"]
class PageIndexQueryPayload(Model):
deleted: bool = False
- limit: Optional[int] = Field(default=100, lt=1000, title="Limit", description="Maximum number of pages to return.")
- offset: Optional[int] = Field(default=0, title="Offset", description="Number of pages to skip.")
- show_own: Optional[bool] = None
- show_published: Optional[bool] = None
- show_shared: Optional[bool] = None
- search: Optional[str] = Field(default=None, title="Filter text", description="Freetext to search.")
+ limit: int | None = Field(default=100, lt=1000, title="Limit", description="Maximum number of pages to return.")
+ offset: int | None = Field(default=0, title="Offset", description="Number of pages to skip.")
+ show_own: bool | None = None
+ show_published: bool | None = None
+ show_shared: bool | None = None
+ search: str | None = Field(default=None, title="Filter text", description="Freetext to search.")
sort_by: PageSortByEnum = Field("update_time", title="Sort By", description="Sort pages by this attribute.")
- sort_desc: Optional[bool] = Field(default=False, title="Sort descending", description="Sort in descending order.")
- user_id: Optional[DecodedDatabaseIdField] = None
- invocation_id: Optional[DecodedDatabaseIdField] = Field(
+ sort_desc: bool | None = Field(default=False, title="Sort descending", description="Sort in descending order.")
+ user_id: DecodedDatabaseIdField | None = None
+ invocation_id: DecodedDatabaseIdField | None = Field(
default=None, title="Invocation ID", description="Filter pages by workflow invocation."
)
- history_id: Optional[DecodedDatabaseIdField] = Field(
+ history_id: DecodedDatabaseIdField | None = Field(
default=None, title="History ID", description="Filter pages by history."
)
class CreateHistoryPayload(Model):
- name: Optional[str] = Field(
+ name: str | None = Field(
default=None,
title="Name",
description="The new history name.",
)
- history_id: Optional[DecodedDatabaseIdField] = Field(
+ history_id: DecodedDatabaseIdField | None = Field(
default=None,
title="History ID",
description=(
"The encoded ID of the history to copy. Provide this value only if you want to copy an existing history."
),
)
- all_datasets: Optional[bool] = Field(
+ all_datasets: bool | None = Field(
default=True,
title="All Datasets",
description=(
"Whether to copy also deleted HDAs/HDCAs. Only applies when providing a `history_id` to copy from."
),
)
- archive_source: Optional[str] = Field(
+ archive_source: str | None = Field(
default=None,
title="Archive Source",
description=("The URL that will generate the archive to import when `archive_type='url'`. "),
)
- archive_type: Optional[HistoryImportArchiveSourceType] = Field(
+ archive_type: HistoryImportArchiveSourceType | None = Field(
default=HistoryImportArchiveSourceType.url,
title="Archive Type",
description="The type of source from where the new history will be imported.",
)
- archive_file: Optional[Any] = Field(
+ archive_file: Any | None = Field(
default=None,
title="Archive File",
description="Uploaded file information when importing the history from a file.",
@@ -1805,7 +1794,7 @@ class CreateHistoryPayload(Model):
class CollectionElementIdentifier(Model):
- name: Optional[str] = Field(
+ name: str | None = Field(
None,
title="Name",
description="The name of the element.",
@@ -1815,18 +1804,18 @@ class CollectionElementIdentifier(Model):
title="Source",
description="The source of the element.",
)
- id: Optional[DecodedDatabaseIdField] = Field(
+ id: DecodedDatabaseIdField | None = Field(
default=None,
title="ID",
description="The encoded ID of the element.",
)
- collection_type: Optional[CollectionType] = OptionalCollectionTypeField
- element_identifiers: Optional[list["CollectionElementIdentifier"]] = Field(
+ collection_type: CollectionType | None = OptionalCollectionTypeField
+ element_identifiers: list["CollectionElementIdentifier"] | None = Field(
default=None,
title="Element Identifiers",
description="List of elements that should be in the new sub-collection.",
)
- tags: Optional[list[str]] = Field(
+ tags: list[str] | None = Field(
default=None,
title="Tags",
description="The list of tags associated with the element.",
@@ -1834,51 +1823,51 @@ class CollectionElementIdentifier(Model):
class CreateNewCollectionPayload(Model):
- collection_type: Optional[CollectionType] = OptionalCollectionTypeField
- element_identifiers: Optional[list[CollectionElementIdentifier]] = Field(
+ collection_type: CollectionType | None = OptionalCollectionTypeField
+ element_identifiers: list[CollectionElementIdentifier] | None = Field(
default=None,
title="Element Identifiers",
description="List of elements that should be in the new collection.",
)
- column_definitions: Optional[SampleSheetColumnDefinitions] = Field(
+ column_definitions: SampleSheetColumnDefinitions | None = Field(
default=None,
title="Column Definitions",
description="Specify definitions for row data if collection_type is sample_sheet",
)
- rows: Optional[SampleSheetRows] = Field(
+ rows: SampleSheetRows | None = Field(
default=None,
title="Row data",
description="Specify rows of metadata data corresponding to an identifier if collection_type is sample_sheet",
)
- name: Optional[str] = Field(
+ name: str | None = Field(
default=None,
title="Name",
description="The name of the new collection.",
)
- hide_source_items: Optional[bool] = Field(
+ hide_source_items: bool | None = Field(
default=False,
title="Hide Source Items",
description="Whether to mark the original HDAs as hidden.",
)
- copy_elements: Optional[bool] = Field(
+ copy_elements: bool | None = Field(
default=True,
title="Copy Elements",
description="Whether to create a copy of the source HDAs for the new collection.",
)
- instance_type: Optional[DatasetCollectionInstanceType] = Field(
+ instance_type: DatasetCollectionInstanceType | None = Field(
default="history",
title="Instance Type",
description="The type of the instance, either `history` (default) or `library`.",
)
- history_id: Optional[DecodedDatabaseIdField] = Field(
+ history_id: DecodedDatabaseIdField | None = Field(
default=None,
description="The ID of the history that will contain the collection. Required if `instance_type=history`.",
)
- folder_id: Optional[LibraryFolderDatabaseIdField] = Field(
+ folder_id: LibraryFolderDatabaseIdField | None = Field(
default=None,
description="The ID of the library folder that will contain the collection. Required if `instance_type=library`.",
)
- fields_: Optional[Union[str, list[FieldDict]]] = Field(
+ fields_: str | list[FieldDict] | None = Field(
default=[],
description="List of fields to create for this collection. Set to 'auto' to guess fields from identifiers.",
alias="fields",
@@ -1918,8 +1907,8 @@ class DiscardedDataType(str, Enum):
class StoreContentSource(Model):
- store_content_uri: Optional[str] = None
- store_dict: Optional[dict[str, Any]] = None
+ store_content_uri: str | None = None
+ store_dict: dict[str, Any] | None = None
model_store_format: Optional["ModelStoreFormat"] = None
discarded_data: DiscardedDataType = Field(
default=DiscardedDataType.ALLOW,
@@ -1964,19 +1953,19 @@ class BcoGenerationParametersMixin(BaseModel):
bco_merge_history_metadata: bool = Field(
default=False, description="When reading tags/annotations to generate BCO object include history metadata."
)
- bco_override_environment_variables: Optional[dict[str, str]] = Field(
+ bco_override_environment_variables: dict[str, str] | None = Field(
default=None,
description="Override environment variables for 'execution_domain' when generating BioCompute object.",
)
- bco_override_empirical_error: Optional[dict[str, str]] = Field(
+ bco_override_empirical_error: dict[str, str] | None = Field(
default=None,
description="Override empirical error for 'error domain' when generating BioCompute object.",
)
- bco_override_algorithmic_error: Optional[dict[str, str]] = Field(
+ bco_override_algorithmic_error: dict[str, str] | None = Field(
default=None,
description="Override algorithmic error for 'error domain' when generating BioCompute object.",
)
- bco_override_xref: Optional[list[XrefItem]] = Field(
+ bco_override_xref: list[XrefItem] | None = Field(
default=None,
description="Override xref for 'description domain' when generating BioCompute object.",
)
@@ -1988,7 +1977,7 @@ class WriteStoreToPayload(StoreExportPayload):
title="Target URI",
description="Galaxy Files URI to write mode store content to.",
)
- ignore_errors: Optional[bool] = Field(
+ ignore_errors: bool | None = Field(
default=None,
description=(
"Last resort. If True, skip serialization errors caused by missing "
@@ -2063,20 +2052,17 @@ def _store_export_payload_discriminator(value: Any) -> str:
class ExportObjectRequestMetadata(Model):
object_id: EncodedDatabaseIdField
object_type: ExportObjectType
- user_id: Optional[EncodedDatabaseIdField] = None
+ user_id: EncodedDatabaseIdField | None = None
payload: Annotated[
- Union[
- Annotated[WriteStoreToPayload, Tag("write")],
- Annotated[ShortTermStoreExportPayload, Tag("short_term")],
- ],
+ Annotated[WriteStoreToPayload, Tag("write")] | Annotated[ShortTermStoreExportPayload, Tag("short_term")],
Discriminator(_store_export_payload_discriminator),
]
class ExportObjectResultMetadata(Model):
success: bool
- uri: Optional[str] = None
- error: Optional[str] = None
+ uri: str | None = None
+ error: str | None = None
@model_validator(mode="after")
def validate_success(self):
@@ -2102,7 +2088,7 @@ class ExportObjectResultMetadata(Model):
class ExportObjectMetadata(Model):
request_data: ExportObjectRequestMetadata
- result_data: Optional[ExportObjectResultMetadata] = None
+ result_data: ExportObjectResultMetadata | None = None
def is_short_term(self):
"""Whether the export is a short term export."""
@@ -2120,7 +2106,7 @@ class ObjectExportTaskResponse(ObjectExportResponseBase):
description="The identifier of the task processing the export.",
)
create_time: datetime = CreateTimeField
- export_metadata: Optional[ExportObjectMetadata] = None
+ export_metadata: ExportObjectMetadata | None = None
class JobExportHistoryArchiveListResponse(RootModel):
@@ -2133,7 +2119,7 @@ class ExportTaskListResponse(RootModel):
class ArchiveHistoryRequestPayload(Model):
- archive_export_id: Optional[DecodedDatabaseIdField] = Field(
+ archive_export_id: DecodedDatabaseIdField | None = Field(
default=None,
title="Export Record ID",
description=(
@@ -2157,7 +2143,7 @@ class ExportRecordData(WriteStoreToPayload):
class ExportAssociationData(Model):
- export_record_data: Optional[ExportRecordData] = Field(
+ export_record_data: ExportRecordData | None = Field(
default=None,
title="Export Record Data",
description="The export record data associated with this archived history. Used to recover the history.",
@@ -2184,11 +2170,7 @@ class CustomArchivedHistoryView(CustomHistoryView, ExportAssociationData):
AnyArchivedHistoryView = Annotated[
- Union[
- CustomArchivedHistoryView,
- ArchivedHistoryDetailed,
- ArchivedHistorySummary,
- ],
+ CustomArchivedHistoryView | ArchivedHistoryDetailed | ArchivedHistorySummary,
Field(union_mode="left_to_right"),
]
@@ -2233,7 +2215,7 @@ class JobIdResponse(Model):
class JobBaseModel(Model, WithModelClass):
id: JobId
- history_id: Optional[EncodedDatabaseIdField] = Field(
+ history_id: EncodedDatabaseIdField | None = Field(
None,
title="History ID",
description="The encoded ID of the history associated with this item.",
@@ -2249,14 +2231,14 @@ class JobBaseModel(Model, WithModelClass):
title="State",
description="Current state of the job.",
)
- exit_code: Optional[int] = Field(
+ exit_code: int | None = Field(
None,
title="Exit Code",
description="The exit code returned by the tool. Can be unset if the job is not completed yet.",
)
create_time: datetime = CreateTimeField
update_time: datetime = UpdateTimeField
- galaxy_version: Optional[str] = Field(
+ galaxy_version: str | None = Field(
default=None,
title="Galaxy Version",
description="The (major) version of Galaxy used to create this job.",
@@ -2295,22 +2277,22 @@ class WorkflowInvocationStateSummary(ItemStateSummary):
class JobSummary(JobBaseModel):
"""Basic information about a job."""
- external_id: Optional[str] = Field(
+ external_id: str | None = Field(
None,
title="External ID",
description="The job id used by the external job runner (Condor, Pulsar, etc.). Only administrator can see this value.",
)
- handler: Optional[str] = Field(
+ handler: str | None = Field(
None,
title="Job Handler",
description="The job handler process assigned to handle this job. Only administrator can see this value.",
)
- job_runner_name: Optional[str] = Field(
+ job_runner_name: str | None = Field(
None,
title="Job Runner Name",
description="Name of the job runner plugin that handles this job. Only administrator can see this value.",
)
- command_line: Optional[str] = Field(
+ command_line: str | None = Field(
None,
title="Command Line",
description=(
@@ -2318,15 +2300,14 @@ class JobSummary(JobBaseModel):
"Users can see this value if allowed in the configuration, administrator can always see this value."
),
)
- user_email: Optional[str] = Field(
+ user_email: str | None = Field(
None,
title="User Email",
description=(
- "The email of the user that owns this job. "
- "Only the owner of the job and administrators can see this value."
+ "The email of the user that owns this job. Only the owner of the job and administrators can see this value."
),
)
- user_id: Optional[EncodedDatabaseIdField] = Field(
+ user_id: EncodedDatabaseIdField | None = Field(
None,
title="User ID",
description="The encoded ID of the user that owns this job.",
@@ -2359,7 +2340,7 @@ class EncodedDataItemSourceId(Model):
class EncodedJobParameterHistoryItem(EncodedDataItemSourceId):
- hid: Optional[int] = None
+ hid: int | None = None
name: str
@@ -2435,8 +2416,8 @@ class JobMetric(Model):
class WorkflowJobMetric(JobMetric):
tool_id: str
job_id: str
- step_index: Union[int, str] # int for top-level steps, str for subworkflow steps (e.g., "1.0")
- step_label: Optional[str]
+ step_index: int | str # int for top-level steps, str for subworkflow steps (e.g., "1.0")
+ step_label: str | None
class JobMetricCollection(RootModel):
@@ -2485,7 +2466,7 @@ class JobFullDetails(JobDetails):
title="Job Messages",
description="List with additional information and possible reasons for a failed job.",
)
- job_metrics: Optional[JobMetricCollection] = Field(
+ job_metrics: JobMetricCollection | None = Field(
None,
title="Job Metrics",
description=(
@@ -2511,7 +2492,7 @@ class StoredWorkflowSummary(Model, WithModelClass):
title="Published",
description="Whether this workflow is currently publicly available to all users.",
)
- annotations: Optional[list[str]] = (
+ annotations: list[str] | None = (
Field( # Inconsistency? Why workflows summaries use a list instead of an optional string?
None,
title="Annotations",
@@ -2534,17 +2515,17 @@ class StoredWorkflowSummary(Model, WithModelClass):
title="Owner",
description="The name of the user who owns this workflow.",
)
- latest_workflow_uuid: Optional[UUID4] = Field(
+ latest_workflow_uuid: UUID4 | None = Field(
None,
title="Latest workflow UUID",
description="TODO",
)
- number_of_steps: Optional[int] = Field(
+ number_of_steps: int | None = Field(
None,
title="Number of Steps",
description="The number of steps that make up this workflow.",
)
- show_in_tool_panel: Optional[bool] = Field(
+ show_in_tool_panel: bool | None = Field(
None,
title="Show in Tool Panel",
description="Whether to display this workflow in the Tools Panel.",
@@ -2552,17 +2533,17 @@ class StoredWorkflowSummary(Model, WithModelClass):
class WorkflowInput(Model):
- label: Optional[str] = Field(
+ label: str | None = Field(
...,
title="Label",
description="Label of the input.",
)
- value: Optional[Any] = Field(
+ value: Any | None = Field(
...,
title="Value",
description="TODO",
)
- uuid: Optional[UUID4] = Field(
+ uuid: UUID4 | None = Field(
...,
title="UUID",
description="Universal unique identifier of the input.",
@@ -2570,7 +2551,7 @@ class WorkflowInput(Model):
class WorkflowOutput(Model):
- label: Optional[str] = Field(
+ label: str | None = Field(
None,
title="Label",
description="Label of the output.",
@@ -2580,7 +2561,7 @@ class WorkflowOutput(Model):
title="Output Name",
description="The name assigned to the output.",
)
- uuid: Optional[UUID4] = Field(
+ uuid: UUID4 | None = Field(
None,
title="UUID",
description="Universal unique identifier of the output.",
@@ -2606,24 +2587,24 @@ class WorkflowStepBase(Model):
title="ID",
description="The identifier of the step. It matches the index order of the step inside the workflow.",
)
- annotation: Optional[str] = AnnotationField
+ annotation: str | None = AnnotationField
input_steps: dict[str, InputStep] = Field(
...,
title="Input Steps",
description="A dictionary containing information about the inputs connected to this workflow step.",
)
- when: Optional[str]
+ when: str | None
# TODO: these should move to ToolStep, however we might be breaking scripts that iterate over steps and
# assume tool_id is a valid key for every step.
- tool_id: Optional[str] = Field(
+ tool_id: str | None = Field(
None, title="Tool ID", description="The unique name of the tool associated with this step."
)
- tool_uuid: Optional[UUID4] = Field(
+ tool_uuid: UUID4 | None = Field(
None,
title="Tool UUID",
description="The universal unique identifier of the tool associated with this step. Takes precedence over tool_id if set.",
)
- tool_version: Optional[str] = Field(
+ tool_version: str | None = Field(
None, title="Tool Version", description="The version of the tool associated with this step."
)
tool_inputs: Any = Field(None, title="Tool Inputs", description="TODO")
@@ -2658,35 +2639,35 @@ class SubworkflowStep(WorkflowStepBase):
class Creator(Model):
class_: str = Field(..., alias="class", title="Class", description="The class representing this creator.")
- name: Optional[str] = Field(None, title="Name", description="The name of the creator.")
- address: Optional[str] = Field(
+ name: str | None = Field(None, title="Name", description="The name of the creator.")
+ address: str | None = Field(
None,
title="Address",
)
- alternate_name: Optional[str] = Field(
+ alternate_name: str | None = Field(
None,
alias="alternateName",
title="Alternate Name",
)
- email: Optional[str] = Field(
+ email: str | None = Field(
None,
title="Email",
)
- fax_number: Optional[str] = Field(
+ fax_number: str | None = Field(
None,
alias="faxNumber",
title="Fax Number",
)
- identifier: Optional[str] = Field(None, title="Identifier", description="Identifier (typically an orcid.org ID)")
- image: Optional[AnyHttpUrl] = Field(
+ identifier: str | None = Field(None, title="Identifier", description="Identifier (typically an orcid.org ID)")
+ image: AnyHttpUrl | None = Field(
None,
title="Image URL",
)
- telephone: Optional[str] = Field(
+ telephone: str | None = Field(
None,
title="Telephone",
)
- url: Optional[AnyHttpUrl] = Field(
+ url: AnyHttpUrl | None = Field(
None,
title="URL",
)
@@ -2704,26 +2685,26 @@ class Person(Creator):
"Person",
alias="class",
)
- family_name: Optional[str] = Field(
+ family_name: str | None = Field(
None,
alias="familyName",
title="Family Name",
)
- givenName: Optional[str] = Field(
+ givenName: str | None = Field(
None,
alias="givenName",
title="Given Name",
)
- honorific_prefix: Optional[str] = Field(
+ honorific_prefix: str | None = Field(
None,
alias="honorificPrefix",
title="Honorific Prefix",
description="Honorific Prefix (e.g. Dr/Mrs/Mr)",
)
- honorific_suffix: Optional[str] = Field(
+ honorific_suffix: str | None = Field(
None, alias="honorificSuffix", title="Honorific Suffix", description="Honorific Suffix (e.g. M.D.)"
)
- job_title: Optional[str] = Field(
+ job_title: str | None = Field(
None,
alias="jobTitle",
title="Job Title",
@@ -2747,7 +2728,7 @@ class InputConnection(Model):
title="Output Name",
description="The name assigned to the output.",
)
- input_subworkflow_step_id: Optional[int] = Field(
+ input_subworkflow_step_id: int | None = Field(
None,
title="Input Subworkflow Step ID",
description="TODO",
@@ -2778,8 +2759,8 @@ class WorkflowStepToExportBase(Model):
)
type: str = Field(..., title="Type", description="The type of workflow module.")
name: str = Field(..., title="Name", description="The descriptive name of the module or step.")
- annotation: Optional[str] = AnnotationField
- tool_id: Optional[str] = Field( # Duplicate of `content_id` or viceversa?
+ annotation: str | None = AnnotationField
+ tool_id: str | None = Field( # Duplicate of `content_id` or viceversa?
None, title="Tool ID", description="The unique name of the tool associated with this step."
)
uuid: UUID4 = Field(
@@ -2787,7 +2768,7 @@ class WorkflowStepToExportBase(Model):
title="UUID",
description="Universal unique identifier of the workflow.",
)
- label: Optional[str] = Field(
+ label: str | None = Field(
None,
title="Label",
)
@@ -2817,10 +2798,8 @@ class WorkflowStepToExportBase(Model):
class WorkflowStepToExport(WorkflowStepToExportBase):
- content_id: Optional[str] = Field( # Duplicate of `tool_id` or viceversa?
- None, title="Content ID", description="TODO"
- )
- tool_version: Optional[str] = Field(
+ content_id: str | None = Field(None, title="Content ID", description="TODO") # Duplicate of `tool_id` or viceversa?
+ tool_version: str | None = Field(
None, title="Tool Version", description="The version of the tool associated with this step."
)
tool_state: Json = Field(
@@ -2828,7 +2807,7 @@ class WorkflowStepToExport(WorkflowStepToExportBase):
title="Tool State",
description="JSON string containing the serialized representation of the persistable state of the step.",
)
- errors: Optional[str] = Field(
+ errors: str | None = Field(
None,
title="Errors",
description="An message indicating possible errors in the step.",
@@ -2902,25 +2881,25 @@ class WorkflowToExport(Model):
description="Whether this workflow is a Galaxy Workflow.",
)
name: str = Field(..., title="Name", description="The name of the workflow.")
- annotation: Optional[str] = AnnotationField
+ annotation: str | None = AnnotationField
tags: TagCollection
- uuid: Optional[UUID4] = Field(
+ uuid: UUID4 | None = Field(
None,
title="UUID",
description="Universal unique identifier of the workflow.",
)
- creator: Optional[list[Union[Person, CreatorOrganization]]] = Field(
+ creator: list[Person | CreatorOrganization] | None = Field(
None,
title="Creator",
description=("Additional information about the creator (or multiple creators) of this workflow."),
)
- license: Optional[str] = Field(
+ license: str | None = Field(
None, title="License", description="SPDX Identifier of the license associated with this workflow."
)
version: int = Field(
..., title="Version", description="The version of the workflow represented by an incremental number."
)
- steps: dict[int, Union[SubworkflowStepToExport, WorkflowToolStepToExport, WorkflowStepToExport]] = Field(
+ steps: dict[int, SubworkflowStepToExport | WorkflowToolStepToExport | WorkflowStepToExport] = Field(
{}, title="Steps", description="A dictionary with information about all the steps of the workflow."
)
@@ -2939,7 +2918,7 @@ class BasicRoleModel(Model):
class RoleModelResponse(BasicRoleModel, WithModelClass):
- description: Optional[RoleDescriptionField]
+ description: RoleDescriptionField | None
url: RelativeUrlField
model_class: Literal["Role"] = ModelClassField(Literal["Role"])
@@ -2947,8 +2926,8 @@ class RoleModelResponse(BasicRoleModel, WithModelClass):
class RoleDefinitionModel(Model):
name: RoleNameField
description: RoleDescriptionField
- user_ids: Optional[list[DecodedDatabaseIdField]] = Field(title="User IDs", default=[])
- group_ids: Optional[list[DecodedDatabaseIdField]] = Field(title="Group IDs", default=[])
+ user_ids: list[DecodedDatabaseIdField] | None = Field(title="User IDs", default=[])
+ group_ids: list[DecodedDatabaseIdField] | None = Field(title="Group IDs", default=[])
role_type: Literal["admin", "user_tool_create", "user_tool_execute"] = "admin"
@@ -3003,7 +2982,7 @@ class ImportToolDataBundleDatasetSource(Model):
id: DecodedDatabaseIdField
-ImportToolDataBundleSource = Union[ImportToolDataBundleDatasetSource, ImportToolDataBundleUriSource]
+ImportToolDataBundleSource = ImportToolDataBundleDatasetSource | ImportToolDataBundleUriSource
class ToolShedRepository(Model):
@@ -3021,12 +3000,12 @@ class ToolShedRepositoryChangeset(ToolShedRepository):
class InstalledRepositoryToolShedStatus(Model):
# See https://github.com/galaxyproject/galaxy/issues/10453 , bad booleans
# See https://github.com/galaxyproject/galaxy/issues/16135 , optional fields
- latest_installable_revision: Optional[str] = Field(
+ latest_installable_revision: str | None = Field(
None, title="Latest installed revision", description="Most recent version available on the tool shed"
)
revision_update: str
- revision_upgrade: Optional[str] = None
- repository_deprecated: Optional[str] = Field(
+ revision_upgrade: str | None = None
+ repository_deprecated: str | None = Field(
None, title="Repository deprecated", description="Repository has been depreciated on the tool shed"
)
@@ -3043,7 +3022,7 @@ class InstalledToolShedRepository(Model, WithModelClass):
owner: str = Field(title="Owner", description="Owner of repository")
deleted: bool
# This should be an int... but it would break backward compatiblity. Probably switch it at some point anyway?
- ctx_rev: Optional[str] = Field(
+ ctx_rev: str | None = Field(
title="Changeset revision number",
description="The linearized 0-based index of the changeset on the tool shed (0, 1, 2,...)",
)
@@ -3058,7 +3037,7 @@ class InstalledToolShedRepository(Model, WithModelClass):
changeset_revision: str = Field(
title="Changeset revision", description="Changeset revision of the repository - a mercurial commit hash"
)
- tool_shed_status: Optional[InstalledRepositoryToolShedStatus] = Field(
+ tool_shed_status: InstalledRepositoryToolShedStatus | None = Field(
None, title="Latest updated status from the tool shed"
)
@@ -3097,12 +3076,12 @@ class LibraryLegacySummary(Model, WithModelClass):
title="Name",
description="The name of the Library.",
)
- description: Optional[str] = Field(
+ description: str | None = Field(
"",
title="Description",
description="A detailed description of the Library.",
)
- synopsis: Optional[str] = Field(
+ synopsis: str | None = Field(
None,
title="Description",
description="A short text describing the contents of the Library.",
@@ -3166,12 +3145,12 @@ class CreateLibraryPayload(Model):
title="Name",
description="The name of the Library.",
)
- description: Optional[str] = Field(
+ description: str | None = Field(
"",
title="Description",
description="A detailed description of the Library.",
)
- synopsis: Optional[str] = Field(
+ synopsis: str | None = Field(
"",
title="Synopsis",
description="A short text describing the contents of the Library.",
@@ -3183,17 +3162,17 @@ class CreateLibrariesFromStore(StoreContentSource):
class UpdateLibraryPayload(Model):
- name: Optional[str] = Field(
+ name: str | None = Field(
None,
title="Name",
description="The new name of the Library. Leave unset to keep the existing.",
)
- description: Optional[str] = Field(
+ description: str | None = Field(
None,
title="Description",
description="A detailed description of the Library. Leave unset to keep the existing.",
)
- synopsis: Optional[str] = Field(
+ synopsis: str | None = Field(
None,
title="Synopsis",
description="A short text describing the contents of the Library. Leave unset to keep the existing.",
@@ -3231,28 +3210,28 @@ class LibraryCurrentPermissions(Model):
)
-RoleIdList = Union[
- list[DecodedDatabaseIdField], DecodedDatabaseIdField
-] # Should we support just List[DecodedDatabaseIdField] in the future?
+RoleIdList = (
+ list[DecodedDatabaseIdField] | DecodedDatabaseIdField
+) # Should we support just List[DecodedDatabaseIdField] in the future?
class LegacyLibraryPermissionsPayload(RequireOneSetOption):
- LIBRARY_ACCESS_in: Optional[RoleIdList] = Field(
+ LIBRARY_ACCESS_in: RoleIdList | None = Field(
[],
title="Access IDs",
description="A list of role encoded IDs defining roles that should have access permission on the library.",
)
- LIBRARY_MODIFY_in: Optional[RoleIdList] = Field(
+ LIBRARY_MODIFY_in: RoleIdList | None = Field(
[],
title="Add IDs",
description="A list of role encoded IDs defining roles that should be able to add items to the library.",
)
- LIBRARY_ADD_in: Optional[RoleIdList] = Field(
+ LIBRARY_ADD_in: RoleIdList | None = Field(
[],
title="Manage IDs",
description="A list of role encoded IDs defining roles that should have manage permission on the library.",
)
- LIBRARY_MANAGE_in: Optional[RoleIdList] = Field(
+ LIBRARY_MANAGE_in: RoleIdList | None = Field(
[],
title="Modify IDs",
description="A list of role encoded IDs defining roles that should have modify permission on the library.",
@@ -3271,19 +3250,19 @@ class DatasetPermissionAction(str, Enum):
class LibraryPermissionsPayloadBase(RequireOneSetOption):
- add_ids: Optional[RoleIdList] = Field(
+ add_ids: RoleIdList | None = Field(
[],
alias="add_ids[]",
title="Add IDs",
description="A list of role encoded IDs defining roles that should be able to add items to the library.",
)
- manage_ids: Optional[RoleIdList] = Field(
+ manage_ids: RoleIdList | None = Field(
[],
alias="manage_ids[]",
title="Manage IDs",
description="A list of role encoded IDs defining roles that should have manage permission on the library.",
)
- modify_ids: Optional[RoleIdList] = Field(
+ modify_ids: RoleIdList | None = Field(
[],
alias="modify_ids[]",
title="Modify IDs",
@@ -3292,12 +3271,12 @@ class LibraryPermissionsPayloadBase(RequireOneSetOption):
class LibraryPermissionsPayload(LibraryPermissionsPayloadBase):
- action: Optional[LibraryPermissionAction] = Field(
+ action: LibraryPermissionAction | None = Field(
None,
title="Action",
description="Indicates what action should be performed on the Library.",
)
- access_ids: Optional[RoleIdList] = Field(
+ access_ids: RoleIdList | None = Field(
[],
alias="access_ids[]", # Added for backward compatibility but it looks really ugly...
title="Access IDs",
@@ -3317,7 +3296,7 @@ FolderNameField: str = Field(
title="Name",
description="The name of the library folder.",
)
-FolderDescriptionField: Optional[str] = Field(
+FolderDescriptionField: str | None = Field(
"",
title="Description",
description="A detailed description of the library folder.",
@@ -3325,7 +3304,7 @@ FolderDescriptionField: Optional[str] = Field(
class LibraryFolderPermissionsPayload(LibraryPermissionsPayloadBase):
- action: Optional[LibraryFolderPermissionAction] = Field(
+ action: LibraryFolderPermissionAction | None = Field(
None,
title="Action",
description="Indicates what action should be performed on the library folder.",
@@ -3340,7 +3319,7 @@ class LibraryFolderDetails(Model, WithModelClass):
description="Encoded ID of the library folder.",
)
name: str = FolderNameField
- description: Optional[str] = FolderDescriptionField
+ description: str | None = FolderDescriptionField
item_count: int = Field(
...,
title="Item Count",
@@ -3351,12 +3330,12 @@ class LibraryFolderDetails(Model, WithModelClass):
title="Parent Library ID",
description="Encoded ID of the Library this folder belongs to.",
)
- parent_id: Optional[EncodedLibraryFolderDatabaseIdField] = Field(
+ parent_id: EncodedLibraryFolderDatabaseIdField | None = Field(
None,
title="Parent Folder ID",
description="Encoded ID of the parent folder. Empty if it's the root folder.",
)
- genome_build: Optional[str] = GenomeBuildField
+ genome_build: str | None = GenomeBuildField
update_time: datetime = UpdateTimeField
deleted: bool = Field(
...,
@@ -3372,16 +3351,16 @@ class LibraryFolderDetails(Model, WithModelClass):
class CreateLibraryFolderPayload(Model):
name: str = FolderNameField
- description: Optional[str] = FolderDescriptionField
+ description: str | None = FolderDescriptionField
class UpdateLibraryFolderPayload(Model):
- name: Optional[str] = Field(
+ name: str | None = Field(
default=None,
title="Name",
description="The new name of the library folder.",
)
- description: Optional[str] = Field(
+ description: str | None = Field(
default=None,
title="Description",
description="The new description of the library folder.",
@@ -3435,10 +3414,10 @@ LibraryFolderContentsIndexSortByEnum = Literal["name", "description", "type", "s
class LibraryFolderContentsIndexQueryPayload(Model):
limit: int = 10
offset: int = 0
- search_text: Optional[str] = None
- include_deleted: Optional[bool] = None
+ search_text: str | None = None
+ include_deleted: bool | None = None
order_by: LibraryFolderContentsIndexSortByEnum = "name"
- sort_desc: Optional[bool] = False
+ sort_desc: bool | None = False
class LibraryFolderItemBase(Model):
@@ -3454,7 +3433,7 @@ class FolderLibraryFolderItem(LibraryFolderItemBase):
id: EncodedLibraryFolderDatabaseIdField
type: Literal["folder"]
can_modify: bool
- description: Optional[str] = FolderDescriptionField
+ description: str | None = FolderDescriptionField
class FileLibraryFolderItem(LibraryFolderItemBase):
@@ -3469,10 +3448,10 @@ class FileLibraryFolderItem(LibraryFolderItemBase):
raw_size: int
ldda_id: EncodedDatabaseIdField
tags: TagCollection
- message: Optional[str] = None
+ message: str | None = None
-AnyLibraryFolderItem = Annotated[Union[FileLibraryFolderItem, FolderLibraryFolderItem], Field(discriminator="type")]
+AnyLibraryFolderItem = Annotated[FileLibraryFolderItem | FolderLibraryFolderItem, Field(discriminator="type")]
class LibraryFolderMetadata(Model):
@@ -3491,12 +3470,12 @@ class LibraryFolderContentsIndexResult(Model):
class CreateLibraryFilePayload(Model):
- from_hda_id: Optional[DecodedDatabaseIdField] = Field(
+ from_hda_id: DecodedDatabaseIdField | None = Field(
default=None,
title="From HDA ID",
description="The ID of an accessible HDA to copy into the library.",
)
- from_hdca_id: Optional[DecodedDatabaseIdField] = Field(
+ from_hdca_id: DecodedDatabaseIdField | None = Field(
default=None,
title="From HDCA ID",
description=(
@@ -3504,7 +3483,7 @@ class CreateLibraryFilePayload(Model):
"Nested collections are not allowed, you must flatten the collection first."
),
)
- ldda_message: Optional[str] = Field(
+ ldda_message: str | None = Field(
default="",
title="LDDA Message",
description="The new message attribute of the LDDA created.",
@@ -3542,7 +3521,7 @@ class DatasetAssociationRoles(Model):
class UpdateDatasetPermissionsPayloadBase(Model):
- action: Optional[DatasetPermissionAction] = Field(
+ action: DatasetPermissionAction | None = Field(
DatasetPermissionAction.set_permissions,
title="Action",
description="Indicates what action should be performed on the dataset.",
@@ -3550,7 +3529,7 @@ class UpdateDatasetPermissionsPayloadBase(Model):
AccessIdsField = Annotated[
- Optional[RoleIdList],
+ RoleIdList | None,
Field(
default=None,
title="Access IDs",
@@ -3559,7 +3538,7 @@ AccessIdsField = Annotated[
]
ManageIdsField = Annotated[
- Optional[RoleIdList],
+ RoleIdList | None,
Field(
default=None,
title="Manage IDs",
@@ -3568,7 +3547,7 @@ ManageIdsField = Annotated[
]
ModifyIdsField = Annotated[
- Optional[RoleIdList],
+ RoleIdList | None,
Field(
default=None,
title="Modify IDs",
@@ -3578,9 +3557,9 @@ ModifyIdsField = Annotated[
class UpdateDatasetPermissionsPayload(UpdateDatasetPermissionsPayloadBase):
- access_ids: Annotated[Optional[RoleIdList], Field(alias="access_ids[]")] = None
- manage_ids: Annotated[Optional[RoleIdList], Field(alias="manage_ids[]")] = None
- modify_ids: Annotated[Optional[RoleIdList], Field(alias="modify_ids[]")] = None
+ access_ids: Annotated[RoleIdList | None, Field(alias="access_ids[]")] = None
+ manage_ids: Annotated[RoleIdList | None, Field(alias="manage_ids[]")] = None
+ modify_ids: Annotated[RoleIdList | None, Field(alias="modify_ids[]")] = None
class UpdateDatasetPermissionsPayloadAliasB(UpdateDatasetPermissionsPayloadBase):
@@ -3595,11 +3574,9 @@ class UpdateDatasetPermissionsPayloadAliasC(UpdateDatasetPermissionsPayloadBase)
modify_ids: ModifyIdsField = None
-UpdateDatasetPermissionsPayloadAliases = Union[
- UpdateDatasetPermissionsPayload,
- UpdateDatasetPermissionsPayloadAliasB,
- UpdateDatasetPermissionsPayloadAliasC,
-]
+UpdateDatasetPermissionsPayloadAliases = (
+ UpdateDatasetPermissionsPayload | UpdateDatasetPermissionsPayloadAliasB | UpdateDatasetPermissionsPayloadAliasC
+)
@partial_model()
@@ -3613,11 +3590,11 @@ class HDACustom(HDADetailed):
# TODO: Fix this workaround for partial_model not supporting UUID fields for some reason.
# The error otherwise is: `PydanticUserError: 'UuidVersion' cannot annotate 'nullable'.`
# Also ignoring mypy complaints about the type redefinition.
- uuid: Optional[UUID4] # type: ignore[assignment]
+ uuid: UUID4 | None # type: ignore[assignment]
# Add fields that are not part of any view here
visualizations: Annotated[
- Optional[list[Visualization]],
+ list[Visualization] | None,
Field(
None,
title="Visualizations",
@@ -3639,28 +3616,21 @@ class HDCACustom(HDCADetailed):
"""
-AnyHDA = Union[HDACustom, HDADetailed, HDASummary, HDAInaccessible]
-AnyHDCA = Union[HDCACustom, HDCADetailed, HDCASummary]
+AnyHDA = HDACustom | HDADetailed | HDASummary | HDAInaccessible
+AnyHDCA = HDCACustom | HDCADetailed | HDCASummary
AnyHistoryContentItem = Annotated[
- Union[
- AnyHDA,
- AnyHDCA,
- ],
+ AnyHDA | AnyHDCA,
Field(union_mode="left_to_right"),
]
AnyJobStateSummary = Annotated[
- Union[
- JobStateSummary,
- ImplicitCollectionJobsStateSummary,
- WorkflowInvocationStateSummary,
- ],
+ JobStateSummary | ImplicitCollectionJobsStateSummary | WorkflowInvocationStateSummary,
Field(..., discriminator="model"),
]
-HistoryArchiveExportResult = Union[JobExportHistoryArchiveModel, JobIdResponse]
+HistoryArchiveExportResult = JobExportHistoryArchiveModel | JobIdResponse
class DeleteHistoryContentPayload(Model):
@@ -3747,7 +3717,7 @@ class ShareWithExtra(Model):
)
-UserIdentifier = Union[DecodedDatabaseIdField, str]
+UserIdentifier = DecodedDatabaseIdField | str
class ShareWithPayload(Model):
@@ -3758,7 +3728,7 @@ class ShareWithPayload(Model):
"A collection of encoded IDs (or email addresses) of users that this resource will be shared with."
),
)
- share_option: Optional[SharingOptions] = Field(
+ share_option: SharingOptions | None = Field(
None,
title="Share Option",
description=(
@@ -3826,17 +3796,17 @@ class SharingStatus(Model):
title="Users shared with",
description="The list of encoded ids for users the resource has been shared.",
)
- email_hash: Optional[str] = Field(
+ email_hash: str | None = Field(
None,
title="Encoded Email",
description="Encoded owner email.",
)
- username: Optional[str] = Field(
+ username: str | None = Field(
None,
title="Username",
description="The owner's username.",
)
- username_and_slug: Optional[str] = Field(
+ username_and_slug: str | None = Field(
None,
title="Username and slug",
description="The relative URL in the form of /u/{username}/{resource_single_char}/{slug}",
@@ -3878,7 +3848,7 @@ class ShareWithStatus(SharingStatus):
title="Errors",
description="Collection of messages indicating that the resource was not shared with some (or all users) due to an error.",
)
- extra: Optional[ShareWithExtra] = Field(
+ extra: ShareWithExtra | None = Field(
None,
title="Extra",
description=(
@@ -3913,13 +3883,13 @@ ContentFormatField: PageContentFormat = Field(
description="Either `markdown` or `html`.",
)
-ContentField: Optional[str] = Field(
+ContentField: str | None = Field(
default="",
title="Content",
description="Text contents of the last page revision with embedded directives expanded (type dependent on content_format).",
)
-ContentEditorField: Optional[str] = Field(
+ContentEditorField: str | None = Field(
default="",
title="Content for Editor",
description="Raw text contents of the last page revision (type dependent on content_format).",
@@ -3933,7 +3903,7 @@ class PageSummaryBase(Model):
description="The name of the page.",
min_length=1,
)
- slug: Optional[str] = Field(
+ slug: str | None = Field(
default=None,
title="Identifier",
description="The identifying slug for the page URL, must be unique. Required for non-history pages.",
@@ -3971,7 +3941,7 @@ class EntityReference(Model):
title="Identifier",
description="The identifier as typed by the user (HID number or name).",
)
- id: Optional[str] = Field(
+ id: str | None = Field(
default=None,
title="Entity ID",
description="The resolved encoded ID of the entity.",
@@ -3981,9 +3951,9 @@ class EntityReference(Model):
title="Name",
description="The display name of the entity.",
)
- extension: Optional[str] = Field(default=None, title="Extension")
- state: Optional[str] = Field(default=None, title="State")
- hid: Optional[int] = Field(default=None, title="HID")
+ extension: str | None = Field(default=None, title="Extension")
+ state: str | None = Field(default=None, title="State")
+ hid: int | None = Field(default=None, title="HID")
class ChatEntityContext(Model):
@@ -3997,27 +3967,27 @@ class ChatPayload(Model):
title="Query",
description="The query to be sent to the chatbot.",
)
- context: Optional[str] = Field(
+ context: str | None = Field(
default="",
title="Context",
description="The context for the chatbot.",
)
- entity_context: Optional[ChatEntityContext] = Field(
+ entity_context: ChatEntityContext | None = Field(
default=None,
title="Entity Context",
description="Structured entity references resolved from @mentions in the query.",
)
- exchange_id: Optional[DecodedDatabaseIdField] = Field(
+ exchange_id: DecodedDatabaseIdField | None = Field(
default=None,
title="Exchange ID",
description="The ID of an existing chat exchange to continue.",
)
- page_id: Optional[DecodedDatabaseIdField] = Field(
+ page_id: DecodedDatabaseIdField | None = Field(
default=None,
title="Page ID",
description="Scope this chat exchange to a history-attached page.",
)
- regenerate: Optional[bool] = Field(
+ regenerate: bool | None = Field(
default=None,
title="Regenerate",
description="Force fresh analysis even if a cached response exists (for job-based queries). Defaults to false if not provided.",
@@ -4030,27 +4000,27 @@ class ChatResponse(BaseModel):
title="Response",
description="The response to the chat query.",
)
- error_code: Optional[int] = Field(
+ error_code: int | None = Field(
...,
title="Error Code",
description="The error code, if any, for the chat query.",
)
- error_message: Optional[str] = Field(
+ error_message: str | None = Field(
...,
title="Error Message",
description="The error message, if any, for the chat query.",
)
- agent_response: Optional[AgentResponse] = Field(
+ agent_response: AgentResponse | None = Field(
default=None,
title="Agent Response",
description="Full structured agent response with metadata and suggestions.",
)
- exchange_id: Optional[EncodedDatabaseIdField] = Field(
+ exchange_id: EncodedDatabaseIdField | None = Field(
default=None,
title="Exchange ID",
description="The ID of the chat exchange for continuing conversations.",
)
- processing_time: Optional[float] = Field(
+ processing_time: float | None = Field(
default=None,
title="Processing Time",
description="Time taken to process the query in seconds.",
@@ -4078,17 +4048,17 @@ class ChatHistoryItemResponse(BaseModel):
title="Agent Type",
description="The type of agent that handled this exchange.",
)
- agent_response: Optional[AgentResponse] = Field(
+ agent_response: AgentResponse | None = Field(
default=None,
title="Agent Response",
description="Full structured agent response with metadata and suggestions.",
)
- timestamp: Optional[str] = Field(
+ timestamp: str | None = Field(
default=None,
title="Timestamp",
description="ISO-format timestamp of the first message in the exchange.",
)
- feedback: Optional[int] = Field(
+ feedback: int | None = Field(
default=None,
title="Feedback",
description="User feedback on the exchange (1 = positive, 0 = negative).",
@@ -4127,24 +4097,24 @@ class GenerateTourResponse(Model):
class CreatePagePayload(PageSummaryBase):
- title: Optional[str] = Field( # type: ignore[assignment]
+ title: str | None = Field( # type: ignore[assignment]
default=None,
title="Title",
description="The name of the page. Auto-generated from history name if not provided for history-attached pages.",
)
content_format: PageContentFormat = ContentFormatField
- content: Optional[str] = ContentField
- annotation: Optional[str] = Field(
+ content: str | None = ContentField
+ annotation: str | None = Field(
default=None,
title="Annotation",
description="Annotation that will be attached to the page.",
)
- invocation_id: Optional[DecodedDatabaseIdField] = Field(
+ invocation_id: DecodedDatabaseIdField | None = Field(
None,
title="Workflow invocation ID",
description="Encoded ID used by workflow generated reports.",
)
- history_id: Optional[DecodedDatabaseIdField] = Field(
+ history_id: DecodedDatabaseIdField | None = Field(
None,
title="History ID",
description="Encoded ID of the history to attach this page to.",
@@ -4153,27 +4123,27 @@ class CreatePagePayload(PageSummaryBase):
class UpdatePagePayload(PageSummaryBase):
- title: Optional[str] = Field( # type: ignore[assignment]
+ title: str | None = Field( # type: ignore[assignment]
default=None,
title="Title",
description="The name of the page.",
min_length=1,
)
- content: Optional[str] = Field(
+ content: str | None = Field(
default=None,
title="Content",
description="New content for the page (creates a new revision).",
)
- content_format: Optional[PageContentFormat] = Field(
+ content_format: PageContentFormat | None = Field(
default=None,
title="Content format",
)
- annotation: Optional[str] = Field(
+ annotation: str | None = Field(
default=None,
title="Annotation",
description="Annotation that will be attached to the page.",
)
- edit_source: Optional[str] = Field(
+ edit_source: str | None = Field(
default=None,
title="Edit source",
description="Source of edit: 'user' or 'agent'.",
@@ -4191,11 +4161,11 @@ class AsyncTaskResultSummary(Model):
title="Ignored",
description="Indicated whether the Celery AsyncResult will be available for retrieval",
)
- name: Optional[str] = Field(
+ name: str | None = Field(
None,
title="Name of task being done derived from Celery AsyncResult",
)
- queue: Optional[str] = Field(
+ queue: str | None = Field(
None,
title="Queue of task being done derived from Celery AsyncResult",
)
@@ -4219,7 +4189,7 @@ class ToolRequestState(str, Enum):
class ToolRequestStateMessage(Model):
err_msg: str
- err_data: Optional[dict[str, Any]] = None
+ err_data: dict[str, Any] | None = None
class ToolRequestModel(Model):
@@ -4228,8 +4198,8 @@ class ToolRequestModel(Model):
# Async-submission lifecycle. NULL on rows captured outside the async
# API path (e.g. workflow tool steps), where no submission lifecycle
# applies.
- state: Optional[ToolRequestState] = None
- state_message: Optional[ToolRequestStateMessage] = None
+ state: ToolRequestState | None = None
+ state_message: ToolRequestStateMessage | None = None
class ToolRequestJobReference(Model):
@@ -4303,12 +4273,12 @@ class PageSummary(PageSummaryBase, WithModelClass):
create_time: datetime = CreateTimeField
update_time: datetime = UpdateTimeField
tags: TagCollection
- source_invocation_id: Optional[EncodedDatabaseIdField] = Field(
+ source_invocation_id: EncodedDatabaseIdField | None = Field(
None,
title="Source Invocation ID",
description="The workflow invocation this page was created from, if any.",
)
- history_id: Optional[EncodedDatabaseIdField] = Field(
+ history_id: EncodedDatabaseIdField | None = Field(
None,
title="History ID",
description="The history this page is attached to, if any.",
@@ -4340,24 +4310,24 @@ class OAuth2State(BaseModel):
class PageDetails(PageSummary):
- annotation: Optional[str] = AnnotationField
+ annotation: str | None = AnnotationField
content_format: PageContentFormat = ContentFormatField
- content: Optional[str] = ContentField
- content_editor: Optional[str] = ContentEditorField
- edit_source: Optional[str] = Field(
+ content: str | None = ContentField
+ content_editor: str | None = ContentEditorField
+ edit_source: str | None = Field(
default=None,
title="Edit source",
description="Source of the latest revision: 'user', 'agent', or 'restore'.",
)
- generate_version: Optional[str] = GenerateVersionField
- generate_time: Optional[str] = GenerateTimeField
+ generate_version: str | None = GenerateVersionField
+ generate_time: str | None = GenerateTimeField
model_config = ConfigDict(extra="allow")
class ToolReportForDataset(BaseModel):
- content: Optional[str] = ContentField
- generate_version: Optional[str] = GenerateVersionField
- generate_time: Optional[str] = GenerateTimeField
+ content: str | None = ContentField
+ generate_version: str | None = GenerateVersionField
+ generate_time: str | None = GenerateTimeField
model_config = ConfigDict(extra="allow")
@@ -4371,16 +4341,16 @@ class PageSummaryList(RootModel):
class PageRevisionSummary(Model):
id: EncodedDatabaseIdField
page_id: EncodedDatabaseIdField
- edit_source: Optional[str] = None
+ edit_source: str | None = None
create_time: datetime
update_time: datetime
class PageRevisionDetails(PageRevisionSummary):
- title: Optional[str] = None
- content: Optional[str] = None
- content_editor: Optional[str] = ContentEditorField
- content_format: Optional[PageContentFormat] = None
+ title: str | None = None
+ content: str | None = None
+ content_editor: str | None = ContentEditorField
+ content_format: PageContentFormat | None = None
class PageRevisionList(RootModel):
@@ -4398,36 +4368,36 @@ WorkflowLandingRequestIdField = Field(title="ID", description="Encoded ID of the
class CreateToolLandingRequestPayload(Model):
tool_id: str
- tool_version: Optional[str] = None
- request_state: Optional[dict[str, Any]] = None
- client_secret: Optional[str] = None
+ tool_version: str | None = None
+ request_state: dict[str, Any] | None = None
+ client_secret: str | None = None
public: bool = False
- origin: Optional[HttpUrl] = Field(None, description="The origin of the landing request.")
+ origin: HttpUrl | None = Field(None, description="The origin of the landing request.")
class CreateWorkflowLandingRequestPayload(Model):
workflow_id: str
workflow_target_type: Literal["stored_workflow", "workflow", "trs_url", "url"]
- request_state: Optional[dict[str, Any]] = None
- client_secret: Optional[str] = None
+ request_state: dict[str, Any] | None = None
+ client_secret: str | None = None
public: bool = Field(
False,
description="If workflow landing request is public anyone with the uuid can use the landing request. If not public the request must be claimed before use and additional verification might occur.",
)
- origin: Optional[HttpUrl] = Field(None, description="The origin of the landing request.")
+ origin: HttpUrl | None = Field(None, description="The origin of the landing request.")
class ClaimLandingPayload(Model):
- client_secret: Optional[str] = None
+ client_secret: str | None = None
class ToolLandingRequest(Model):
uuid: UuidField
tool_id: str
- tool_version: Optional[str] = None
- request_state: Optional[dict[str, Any]] = None
+ tool_version: str | None = None
+ request_state: dict[str, Any] | None = None
state: LandingRequestState
- origin: Optional[HttpUrl] = None
+ origin: HttpUrl | None = None
class WorkflowLandingRequest(Model):
@@ -4436,7 +4406,7 @@ class WorkflowLandingRequest(Model):
workflow_target_type: Literal["stored_workflow", "workflow", "trs_url", "url"]
request_state: dict[str, Any]
state: LandingRequestState
- origin: Optional[HttpUrl] = None
+ origin: HttpUrl | None = None
class MessageExceptionModel(BaseModel):
diff --git a/lib/galaxy/schema/storage_cleaner.py b/lib/galaxy/schema/storage_cleaner.py
index a7de24ca60c..0f2305205bf 100644
--- a/lib/galaxy/schema/storage_cleaner.py
+++ b/lib/galaxy/schema/storage_cleaner.py
@@ -2,7 +2,6 @@ from datetime import datetime
from enum import Enum
from typing import (
Literal,
- Union,
)
from pydantic import Field
@@ -30,7 +29,7 @@ class CleanableItemsSummary(Model):
)
-StoredItemType = Union[Literal["history"], Literal["dataset"]]
+StoredItemType = Literal["history"] | Literal["dataset"]
class StoredItem(Model):
diff --git a/lib/galaxy/schema/storage_operations.py b/lib/galaxy/schema/storage_operations.py
index ed7b91b2c20..fe23721d7c2 100644
--- a/lib/galaxy/schema/storage_operations.py
+++ b/lib/galaxy/schema/storage_operations.py
@@ -3,7 +3,6 @@ from datetime import datetime
from enum import Enum
from typing import (
Any,
- Optional,
)
from pydantic import (
@@ -69,7 +68,7 @@ class DatasetStorageOperationFailureReasonCode(str, Enum):
class StorageOperationPreviewRequest(Model):
mode: StorageOperationMode
target_object_store_id: str
- items: Optional[list[dict[str, Any]]] = None
+ items: list[dict[str, Any]] | None = None
class StorageOperationSelectionCounts(Model):
@@ -103,7 +102,7 @@ class StorageOperationQuotaProjectionSummary(Model):
class StorageOperationEstimateSummary(Model):
bytes_to_transfer: int = 0
quota_delta_transfers: list[StorageOperationQuotaDeltaTransfer] = Field(default_factory=list)
- quota_projection: Optional[StorageOperationQuotaProjectionSummary] = None
+ quota_projection: StorageOperationQuotaProjectionSummary | None = None
class StorageOperationPreviewResponse(Model):
@@ -117,7 +116,7 @@ class StorageOperationPreviewResponse(Model):
class StorageOperationExecutePolicy(Model):
skip_ineligible: bool = True
- max_retries: Optional[int] = None
+ max_retries: int | None = None
class StorageOperationExecuteRequest(Model):
@@ -138,13 +137,13 @@ class StorageOperationRunSummary(Model):
failed_count: int
skipped_count: int
total_bytes_processed: int
- task_id: Optional[UUID4] = None
+ task_id: UUID4 | None = None
class StorageOperationRunItemStatus(Model):
dataset_id: EncodedDatabaseIdField
state: StorageOperationRunItemState
- reason_code: Optional[DatasetStorageOperationFailureReasonCode] = None
+ reason_code: DatasetStorageOperationFailureReasonCode | None = None
bytes_processed: int
create_time: datetime = CreateTimeField
update_time: datetime = UpdateTimeField
diff --git a/lib/galaxy/schema/tasks.py b/lib/galaxy/schema/tasks.py
index 55a46447ba4..cf7a5a491fa 100644
--- a/lib/galaxy/schema/tasks.py
+++ b/lib/galaxy/schema/tasks.py
@@ -1,7 +1,6 @@
from enum import Enum
from typing import (
Literal,
- Optional,
)
from uuid import UUID
@@ -43,14 +42,14 @@ class GeneratePdfDownload(Model):
# serialize user info for tasks
class RequestUser(Model):
- user_id: Optional[int] = None
- galaxy_session_id: Optional[int] = None
+ user_id: int | None = None
+ galaxy_session_id: int | None = None
class GenerateHistoryDownload(ShortTermStoreExportPayload):
history_id: int
user: RequestUser
- export_association_id: Optional[int] = None
+ export_association_id: int | None = None
class GenerateHistoryContentDownload(ShortTermStoreExportPayload):
@@ -66,13 +65,13 @@ class BcoGenerationTaskParametersMixin(BcoGenerationParametersMixin):
class GenerateInvocationDownload(ShortTermStoreExportPayload, BcoGenerationTaskParametersMixin):
invocation_id: int
user: RequestUser
- export_association_id: Optional[int] = None
+ export_association_id: int | None = None
class WriteInvocationTo(WriteStoreToPayload, BcoGenerationTaskParametersMixin):
invocation_id: int
user: RequestUser
- export_association_id: Optional[int] = None
+ export_association_id: int | None = None
class WriteHistoryContentTo(WriteStoreToPayload):
@@ -84,15 +83,15 @@ class WriteHistoryContentTo(WriteStoreToPayload):
class WriteHistoryTo(WriteStoreToPayload):
history_id: int
user: RequestUser
- export_association_id: Optional[int] = None
+ export_association_id: int | None = None
class ImportModelStoreTaskRequest(Model):
user: RequestUser
- history_id: Optional[int] = None
+ history_id: int | None = None
source_uri: str
for_library: bool
- model_store_format: Optional[ModelStoreFormat] = None
+ model_store_format: ModelStoreFormat | None = None
class MaterializeDatasetInstanceTaskRequest(Model):
@@ -114,9 +113,9 @@ class MaterializeDatasetInstanceTaskRequest(Model):
class ComputeDatasetHashTaskRequest(Model):
dataset_id: int
- extra_files_path: Optional[str] = None
+ extra_files_path: str | None = None
hash_function: HashFunctionNameEnum
- user: Optional[RequestUser] = None # access checks should be done pre-celery so this is optional
+ user: RequestUser | None = None # access checks should be done pre-celery so this is optional
class CopyDatasetsPayloadSourceEntry(Model):
@@ -126,8 +125,8 @@ class CopyDatasetsPayloadSourceEntry(Model):
class CopyDatasetsPayload(Model):
source_content: list[CopyDatasetsPayloadSourceEntry]
- target_history_ids: Optional[list[str]] = None
- target_history_name: Optional[str] = None
+ target_history_ids: list[str] | None = None
+ target_history_name: str | None = None
class CopyDatasetsResponse(Model):
@@ -180,9 +179,9 @@ TOOL_SOURCE_CLASS = Literal["XmlToolSource", "YamlToolSource", "CwlToolSource"]
class ToolSource(Model):
raw_tool_source: str
- tool_dir: Optional[str] = None
+ tool_dir: str | None = None
tool_source_class: TOOL_SOURCE_CLASS = "XmlToolSource"
- tool_id: Optional[str] = None
+ tool_id: str | None = None
class QueueJobs(Model):
@@ -190,10 +189,10 @@ class QueueJobs(Model):
tool_request_id: int # links to request ("incoming") and history
user: RequestUser # TODO: test anonymous users through this submission path
use_cached_jobs: bool
- rerun_remap_job_id: Optional[int] # link to a job to rerun & remap
- preferred_object_store_id: Optional[str] = None
- tags: Optional[list[str]] = None
- data_manager_mode: Optional[str] = None
+ rerun_remap_job_id: int | None # link to a job to rerun & remap
+ preferred_object_store_id: str | None = None
+ tags: list[str] | None = None
+ data_manager_mode: str | None = None
send_email_notification: bool = False
- credentials_context: Optional[list[dict]] = None
- dynamic_tool_id: Optional[int] = None # link to DynamicTool for custom/user tools
+ credentials_context: list[dict] | None = None
+ dynamic_tool_id: int | None = None # link to DynamicTool for custom/user tools
diff --git a/lib/galaxy/schema/tours.py b/lib/galaxy/schema/tours.py
index 0d714998607..183cfc1e6db 100644
--- a/lib/galaxy/schema/tours.py
+++ b/lib/galaxy/schema/tours.py
@@ -1,8 +1,4 @@
from enum import Enum
-from typing import (
- Optional,
- Union,
-)
from pydantic import (
BaseModel,
@@ -37,26 +33,26 @@ class TourList(RootModel):
class TourStep(BaseModel):
- title: Optional[str] = Field(None, title="Title", description="Title displayed in the header of the step container")
- content: Optional[str] = Field(None, title="Content", description="Text shown to the user")
- element: Optional[str] = Field(
+ title: str | None = Field(None, title="Title", description="Title displayed in the header of the step container")
+ content: str | None = Field(None, title="Content", description="Text shown to the user")
+ element: str | None = Field(
None, title="Element", description="CSS selector for the element to be described/clicked"
)
- placement: Optional[str] = Field(
+ placement: str | None = Field(
None, title="Placement", description="Placement of the text box relative to the selected element"
)
- preclick: Optional[Union[bool, list[str]]] = Field(
+ preclick: bool | list[str] | None = Field(
None, title="Pre-click", description="Elements that receive a click() event before the step is shown"
)
- postclick: Optional[Union[bool, list[str]]] = Field(
+ postclick: bool | list[str] | None = Field(
None, title="Post-click", description="Elements that receive a click() event after the step is shown"
)
- textinsert: Optional[str] = Field(
+ textinsert: str | None = Field(
None, title="Text-insert", description="Text to insert if element is a text box (e.g. tool search or upload)"
)
- orphan: Optional[bool] = Field(None, title="Orphan", description="If true, the step is an orphan step")
+ orphan: bool | None = Field(None, title="Orphan", description="If true, the step is an orphan step")
class TourDetails(TourCore):
- title_default: Optional[str] = Field(None, title="Default title", description="Default title for each step")
+ title_default: str | None = Field(None, title="Default title", description="Default title for each step")
steps: list[TourStep] = Field(title="Steps", description="Tour steps")
diff --git a/lib/galaxy/schema/types.py b/lib/galaxy/schema/types.py
index 8cfce956ba1..699ad2f1f47 100644
--- a/lib/galaxy/schema/types.py
+++ b/lib/galaxy/schema/types.py
@@ -2,7 +2,6 @@ from datetime import datetime
from typing import (
Annotated,
Literal,
- Union,
)
from pydantic import ValidationInfo
@@ -29,5 +28,5 @@ def strip_tzinfo(v: datetime, info: ValidationInfo) -> datetime:
OffsetNaiveDatetime = Annotated[datetime, AfterValidator(strip_tzinfo)]
CoercedStringType = Annotated[
- Union[str, int, float, bool], AfterValidator(lambda val: val if isinstance(val, str) else str(val))
+ str | int | float | bool, AfterValidator(lambda val: val if isinstance(val, str) else str(val))
]
diff --git a/lib/galaxy/schema/visualization.py b/lib/galaxy/schema/visualization.py
index 161bada52e6..28a6b4ad9d7 100644
--- a/lib/galaxy/schema/visualization.py
+++ b/lib/galaxy/schema/visualization.py
@@ -1,8 +1,6 @@
from datetime import datetime
from typing import (
Literal,
- Optional,
- Union,
)
from pydantic import (
@@ -33,17 +31,17 @@ VISUALIZATION_REVISION_MODEL_CLASS = Literal["VisualizationRevision"]
class VisualizationIndexQueryPayload(Model):
deleted: bool = False
- show_own: Optional[bool] = None
- show_published: Optional[bool] = None
- show_shared: Optional[bool] = None
- user_id: Optional[DecodedDatabaseIdField] = None
+ show_own: bool | None = None
+ show_published: bool | None = None
+ show_shared: bool | None = None
+ user_id: DecodedDatabaseIdField | None = None
sort_by: VisualizationSortByEnum = Field(
"update_time", title="Sort By", description="Sort pages by this attribute."
)
- sort_desc: Optional[bool] = Field(default=True, title="Sort descending", description="Sort in descending order.")
- search: Optional[str] = Field(default=None, title="Filter text", description="Freetext to search.")
- limit: Optional[int] = Field(default=100, lt=1000, title="Limit", description="Maximum number of pages to return.")
- offset: Optional[int] = Field(default=0, title="Offset", description="Number of pages to skip.")
+ sort_desc: bool | None = Field(default=True, title="Sort descending", description="Sort in descending order.")
+ search: str | None = Field(default=None, title="Filter text", description="Freetext to search.")
+ limit: int | None = Field(default=100, lt=1000, title="Limit", description="Maximum number of pages to return.")
+ offset: int | None = Field(default=0, title="Offset", description="Number of pages to skip.")
class VisualizationSummary(Model):
@@ -52,12 +50,12 @@ class VisualizationSummary(Model):
title="ID",
description="Encoded ID of the Visualization.",
)
- annotation: Optional[str] = Field(
+ annotation: str | None = Field(
default=None,
title="Annotation",
description="The annotation of this Visualization.",
)
- dbkey: Optional[str] = Field(
+ dbkey: str | None = Field(
default=None,
title="DbKey",
description="The database key of the visualization.",
@@ -77,7 +75,7 @@ class VisualizationSummary(Model):
title="Published",
description="Whether this Visualization has been published.",
)
- tags: Optional[TagCollection] = Field(
+ tags: TagCollection | None = Field(
...,
title="Tags",
description="A list of tags to add to this item.",
@@ -96,8 +94,8 @@ class VisualizationSummary(Model):
title="Username",
description="The name of the user owning this Visualization.",
)
- create_time: Optional[datetime] = CreateTimeField
- update_time: Optional[datetime] = UpdateTimeField
+ create_time: datetime | None = CreateTimeField
+ update_time: datetime | None = UpdateTimeField
model_config = ConfigDict(extra="allow")
@@ -125,7 +123,7 @@ class VisualizationRevisionResponse(Model, WithModelClass):
title="Title",
description="The name of the visualization revision.",
)
- dbkey: Optional[str] = Field(
+ dbkey: str | None = Field(
None,
title="DbKey",
description="The database key of the visualization.",
@@ -153,12 +151,12 @@ class VisualizationPluginResponse(Model):
title="Description",
description="The description of the plugin.",
)
- logo: Optional[str] = Field(
+ logo: str | None = Field(
None,
title="Logo",
description="The logo of the plugin.",
)
- title: Optional[str] = Field(
+ title: str | None = Field(
None,
title="Title",
description="The title of the plugin.",
@@ -173,42 +171,42 @@ class VisualizationPluginResponse(Model):
title="Entry Point",
description="The entry point of the plugin.",
)
- settings: Optional[list[dict]] = Field(
+ settings: list[dict] | None = Field(
None,
title="Settings",
description="The settings of the plugin.",
)
- tracks: Optional[list[dict]] = Field(
+ tracks: list[dict] | None = Field(
None,
title="Tracks",
description="The tracks of the plugin.",
)
- specs: Optional[dict] = Field(
+ specs: dict | None = Field(
None,
title="Specs",
description="The specs of the plugin.",
)
- params: Optional[dict] = Field(
+ params: dict | None = Field(
None,
title="Params",
description="The parameters of the plugin.",
)
- data_sources: Optional[list[dict]] = Field(
+ data_sources: list[dict] | None = Field(
None,
title="Data Sources",
description="The data sources of the plugin.",
)
- help: Optional[str] = Field(
+ help: str | None = Field(
None,
title="Help",
description="The help text of the plugin.",
)
- tags: Optional[list[str]] = Field(
+ tags: list[str] | None = Field(
None,
title="Tags",
description="The tags of the plugin.",
)
- tests: Optional[list[dict]] = Field(
+ tests: list[dict] | None = Field(
None,
title="Tests",
description="The tests of the plugin.",
@@ -242,12 +240,12 @@ class VisualizationShowResponse(Model, WithModelClass):
title="User ID",
description="The ID of the user owning this Visualization.",
)
- dbkey: Optional[str] = Field(
+ dbkey: str | None = Field(
None,
title="DbKey",
description="The database key of the visualization.",
)
- slug: Optional[str] = Field(
+ slug: str | None = Field(
None,
title="Slug",
description="The slug of the visualization.",
@@ -277,17 +275,17 @@ class VisualizationShowResponse(Model, WithModelClass):
title="Email Hash",
description="The hash of the email of the user owning this Visualization.",
)
- tags: Optional[TagCollection] = Field(
+ tags: TagCollection | None = Field(
None,
title="Tags",
description="A list of tags to add to this item.",
)
- annotation: Optional[str] = Field(
+ annotation: str | None = Field(
None,
title="Annotation",
description="The annotation of this Visualization.",
)
- plugin: Optional[VisualizationPluginResponse] = Field(
+ plugin: VisualizationPluginResponse | None = Field(
None,
title="Plugin",
description="The plugin of this Visualization.",
@@ -321,28 +319,28 @@ class VisualizationCreatePayload(Model):
title="Type",
description="The type of the visualization.",
)
- title: Optional[SanitizedString] = Field(
+ title: SanitizedString | None = Field(
SanitizedString("Untitled Visualization"),
title="Title",
description="The name of the visualization.",
min_length=3,
)
- dbkey: Optional[SanitizedString] = Field(
+ dbkey: SanitizedString | None = Field(
None,
title="DbKey",
description="The database key of the visualization.",
)
- slug: Optional[SanitizedString] = Field(
+ slug: SanitizedString | None = Field(
None,
title="Slug",
description="The slug of the visualization.",
)
- annotation: Optional[SanitizedString] = Field(
+ annotation: SanitizedString | None = Field(
None,
title="Annotation",
description="The annotation of the visualization.",
)
- config: Optional[dict] = Field(
+ config: dict | None = Field(
{},
title="Config",
description="The config of the visualization.",
@@ -350,22 +348,22 @@ class VisualizationCreatePayload(Model):
class VisualizationUpdatePayload(Model):
- title: Optional[SanitizedString] = Field(
+ title: SanitizedString | None = Field(
None,
title="Title",
description="The name of the visualization.",
)
- dbkey: Optional[SanitizedString] = Field(
+ dbkey: SanitizedString | None = Field(
None,
title="DbKey",
description="The database key of the visualization.",
)
- deleted: Optional[bool] = Field(
+ deleted: bool | None = Field(
False,
title="Deleted",
description="Whether this Visualization has been deleted.",
)
- config: Optional[Union[dict, bytes]] = Field(
+ config: dict | bytes | None = Field(
{},
title="Config",
description="The config of the visualization.",
diff --git a/lib/galaxy/schema/wes/__init__.py b/lib/galaxy/schema/wes/__init__.py
index 3e1b2a6564e..723939e26be 100644
--- a/lib/galaxy/schema/wes/__init__.py
+++ b/lib/galaxy/schema/wes/__init__.py
@@ -7,8 +7,6 @@ from __future__ import annotations
from enum import Enum
from typing import (
Any,
- Optional,
- Union,
)
from pydantic import (
@@ -47,7 +45,7 @@ class ServiceType(BaseModel):
class RunId(BaseModel):
- run_id: Optional[str] = Field(None, description="workflow run ID")
+ run_id: str | None = Field(None, description="workflow run ID")
class State(Enum):
@@ -66,14 +64,14 @@ class State(Enum):
class RunStatus(BaseModel):
run_id: str
- state: Optional[State] = None
+ state: State | None = None
class RunSummary(RunStatus):
- start_time: Optional[str] = Field(
+ start_time: str | None = Field(
None, description='When the run started executing, in ISO 8601 format "%Y-%m-%dT%H:%M:%SZ"'
)
- end_time: Optional[str] = Field(
+ end_time: str | None = Field(
None,
description='When the run stopped executing (completed, failed, or cancelled), in ISO 8601 format "%Y-%m-%dT%H:%M:%SZ"',
)
@@ -81,7 +79,7 @@ class RunSummary(RunStatus):
class RunRequest(BaseModel):
- workflow_params: Optional[dict[str, Any]] = Field(
+ workflow_params: dict[str, Any] | None = Field(
None,
description="REQUIRED\nThe workflow run parameterizations (JSON encoded), including input and output file locations",
)
@@ -92,13 +90,13 @@ class RunRequest(BaseModel):
workflow_type_version: str = Field(
..., description="REQUIRED\nThe workflow descriptor type version, must be one supported by this WES instance"
)
- tags: Optional[dict[str, str]] = None
- workflow_engine_parameters: Optional[dict[str, str]] = None
- workflow_engine: Optional[str] = Field(
+ tags: dict[str, str] | None = None
+ workflow_engine_parameters: dict[str, str] | None = None
+ workflow_engine: str | None = Field(
None,
description="The workflow engine, must be one supported by this WES instance. Required if workflow_engine_version is provided.",
)
- workflow_engine_version: Optional[str] = Field(
+ workflow_engine_version: str | None = Field(
None,
description="The workflow engine version, must be one supported by this WES instance. If workflow_engine is provided, but workflow_engine_version is not, servers can make no assumptions with regard to the engine version the WES instance uses to process the request if that WES instance supports multiple versions of the requested engine.",
)
@@ -109,51 +107,51 @@ class RunRequest(BaseModel):
class Log(BaseModel):
- name: Optional[str] = Field(None, description="The task or workflow name")
- cmd: Optional[list[str]] = Field(None, description="The command line that was executed")
- start_time: Optional[str] = Field(
+ name: str | None = Field(None, description="The task or workflow name")
+ cmd: list[str] | None = Field(None, description="The command line that was executed")
+ start_time: str | None = Field(
None, description='When the command started executing, in ISO 8601 format "%Y-%m-%dT%H:%M:%SZ"'
)
- end_time: Optional[str] = Field(
+ end_time: str | None = Field(
None,
description='When the command stopped executing (completed, failed, or cancelled), in ISO 8601 format "%Y-%m-%dT%H:%M:%SZ"',
)
- stdout: Optional[str] = Field(
+ stdout: str | None = Field(
None,
description="A URL to retrieve standard output logs of the workflow run or task. This URL may change between status requests, or may not be available until the task or workflow has finished execution. Should be available using the same credentials used to access the WES endpoint.",
)
- stderr: Optional[str] = Field(
+ stderr: str | None = Field(
None,
description="A URL to retrieve standard error logs of the workflow run or task. This URL may change between status requests, or may not be available until the task or workflow has finished execution. Should be available using the same credentials used to access the WES endpoint.",
)
- exit_code: Optional[int] = Field(None, description="Exit code of the program")
- system_logs: Optional[list[str]] = Field(
+ exit_code: int | None = Field(None, description="Exit code of the program")
+ system_logs: list[str] | None = Field(
None,
description="System logs are any logs the system decides are relevant,\nwhich are not tied directly to a workflow.\nContent is implementation specific: format, size, etc.\n\nSystem logs may be collected here to provide convenient access.\n\nFor example, the system may include an error message that caused\na SYSTEM_ERROR state (e.g. disk is full), etc.",
)
class DefaultWorkflowEngineParameter(BaseModel):
- name: Optional[str] = Field(None, description="The name of the parameter")
- type: Optional[str] = Field(None, description="Describes the type of the parameter, e.g. float.")
- default_value: Optional[str] = Field(
+ name: str | None = Field(None, description="The name of the parameter")
+ type: str | None = Field(None, description="Describes the type of the parameter, e.g. float.")
+ default_value: str | None = Field(
None, description='The stringified version of the default parameter. e.g. "2.45".'
)
class WorkflowTypeVersion(BaseModel):
- workflow_type_version: Optional[list[str]] = Field(
+ workflow_type_version: list[str] | None = Field(
None, description="an array of one or more acceptable types for the `workflow_type`"
)
class TaskLog(Log):
id: str = Field(..., description="A unique identifier which may be used to reference the task")
- system_logs: Optional[list[str]] = Field(
+ system_logs: list[str] | None = Field(
None,
description="System logs are any logs the system decides are relevant,\nwhich are not tied directly to a task.\nContent is implementation specific: format, size, etc.\n\nSystem logs may be collected here to provide convenient access.\n\nFor example, the system may include the name of the host\nwhere the task is executing, an error message that caused\na SYSTEM_ERROR state (e.g. disk is full), etc.",
)
- tes_uri: Optional[str] = Field(
+ tes_uri: str | None = Field(
None,
description="An optional URL pointing to an extended task definition defined by a [TES api](https://github.com/ga4gh/task-execution-schemas)",
)
@@ -161,27 +159,25 @@ class TaskLog(Log):
class WorkflowEngineVersion(BaseModel):
- workflow_engine_version: Optional[list[str]] = Field(
+ workflow_engine_version: list[str] | None = Field(
None, description="An array of one or more acceptable engines versions for the `workflow_engine`"
)
class RunListResponse(BaseModel):
- runs: Optional[list[Union[RunStatus, RunSummary]]] = Field(
+ runs: list[RunStatus | RunSummary] | None = Field(
None,
description="A list of workflow runs that the service has executed or is executing. The list is filtered to only include runs that the caller has permission to see.",
)
- next_page_token: Optional[str] = Field(
+ next_page_token: str | None = Field(
None,
description="A token which may be supplied as `page_token` in workflow run list request to get the next page of results. An empty string indicates there are no more items to return.",
)
class ErrorResponse(BaseModel):
- msg: Optional[str] = Field(None, description="A detailed error message.")
- status_code: Optional[int] = Field(
- None, description="The integer representing the HTTP status code (e.g. 200, 404)."
- )
+ msg: str | None = Field(None, description="A detailed error message.")
+ status_code: int | None = Field(None, description="The integer representing the HTTP status code (e.g. 200, 404).")
class Service(BaseModel):
@@ -192,33 +188,33 @@ class Service(BaseModel):
)
name: str = Field(..., description="Name of this service. Should be human readable.", examples=["My project"])
type: ServiceType
- description: Optional[str] = Field(
+ description: str | None = Field(
None,
description="Description of the service. Should be human readable and provide information about the service.",
examples=["This service provides..."],
)
organization: Organization = Field(..., description="Organization providing the service")
- contactUrl: Optional[AnyUrl] = Field(
+ contactUrl: AnyUrl | None = Field(
None,
description="URL of the contact for the provider of this service, e.g. a link to a contact form (RFC 3986 format), or an email (RFC 2368 format).",
examples=["mailto:support@example.com"],
)
- documentationUrl: Optional[AnyUrl] = Field(
+ documentationUrl: AnyUrl | None = Field(
None,
description="URL of the documentation of this service (RFC 3986 format). This should help someone learn how to use your service, including any specifics required to access data, e.g. authentication.",
examples=["https://docs.myservice.example.com"],
)
- createdAt: Optional[AwareDatetime] = Field(
+ createdAt: AwareDatetime | None = Field(
None,
description="Timestamp describing when the service was first deployed and available (RFC 3339 format)",
examples=["2019-06-04T12:58:19Z"],
)
- updatedAt: Optional[AwareDatetime] = Field(
+ updatedAt: AwareDatetime | None = Field(
None,
description="Timestamp describing when the service was last updated (RFC 3339 format)",
examples=["2019-06-04T12:58:19Z"],
)
- environment: Optional[str] = Field(
+ environment: str | None = Field(
None,
description="Environment the service is running in. Use this to distinguish between production, development and testing/staging deployments. Suggested values are prod, test, dev, staging. However this is advised and not enforced.",
examples=["test"],
@@ -231,26 +227,26 @@ class Service(BaseModel):
class RunLog(BaseModel):
- run_id: Optional[str] = Field(None, description="workflow run ID")
- request: Optional[RunRequest] = None
- state: Optional[State] = None
- run_log: Optional[Log] = None
- task_logs_url: Optional[str] = Field(
+ run_id: str | None = Field(None, description="workflow run ID")
+ request: RunRequest | None = None
+ state: State | None = None
+ run_log: Log | None = None
+ task_logs_url: str | None = Field(
None,
description="A reference to the complete url which may be used to obtain a paginated list of task logs for this workflow",
)
- task_logs: Optional[list[Union[Log, TaskLog]]] = Field(
+ task_logs: list[Log | TaskLog] | None = Field(
None,
description="The logs, and other key info like timing and exit code, for each step in the workflow run. This field is deprecated and the `task_logs_url` should be used to retrieve a paginated list of steps from the workflow run. This field will be removed in the next major version of the specification (2.0.0)",
)
- outputs: Optional[dict[str, Any]] = Field(None, description="The outputs from the workflow run.")
+ outputs: dict[str, Any] | None = Field(None, description="The outputs from the workflow run.")
class TaskListResponse(BaseModel):
- task_logs: Optional[list[TaskLog]] = Field(
+ task_logs: list[TaskLog] | None = Field(
None, description="The logs, and other key info like timing and exit code, for each step in the workflow run."
)
- next_page_token: Optional[str] = Field(
+ next_page_token: str | None = Field(
None,
description="A token which may be supplied as `page_token` in workflow run task list request to get the next page of results. An empty string indicates there are no more items to return.",
)
diff --git a/lib/galaxy/schema/workflow/comments.py b/lib/galaxy/schema/workflow/comments.py
index e41763d383b..95658bf7210 100644
--- a/lib/galaxy/schema/workflow/comments.py
+++ b/lib/galaxy/schema/workflow/comments.py
@@ -1,7 +1,5 @@
from typing import (
Literal,
- Optional,
- Union,
)
from pydantic import (
@@ -21,10 +19,8 @@ class BaseComment(BaseModel):
class TextCommentData(BaseModel):
- bold: Optional[bool] = Field(
- default=None, description="If the Comments text is bold. Absent is interpreted as false"
- )
- italic: Optional[bool] = Field(
+ bold: bool | None = Field(default=None, description="If the Comments text is bold. Absent is interpreted as false")
+ italic: bool | None = Field(
default=None, description="If the Comments text is italic. Absent is interpreted as false"
)
size: int = Field(..., description="Relative size (1 -> 100%) of the text compared to the default text sitz")
@@ -52,10 +48,10 @@ class FrameCommentData(BaseModel):
class FrameComment(BaseComment):
type: Literal["frame"]
data: FrameCommentData
- child_comments: Optional[list[int]] = Field(
+ child_comments: list[int] | None = Field(
default=None, description="A list of ids (see `id`) of all Comments which are encompassed by this Frame"
)
- child_steps: Optional[list[int]] = Field(
+ child_steps: list[int] | None = Field(
default=None, description="A list of ids of all Steps (see WorkflowStep.id) which are encompassed by this Frame"
)
@@ -74,4 +70,4 @@ class FreehandComment(BaseComment):
class WorkflowCommentModel(RootModel):
- root: Union[TextComment, MarkdownComment, FrameComment, FreehandComment] = Field(..., discriminator="type")
+ root: TextComment | MarkdownComment | FrameComment | FreehandComment = Field(..., discriminator="type")
diff --git a/lib/galaxy/schema/workflows.py b/lib/galaxy/schema/workflows.py
index 1179041b3cd..bbefcd48f0c 100644
--- a/lib/galaxy/schema/workflows.py
+++ b/lib/galaxy/schema/workflows.py
@@ -4,8 +4,6 @@ from typing import (
Annotated,
Any,
Literal,
- Optional,
- Union,
)
from pydantic import (
@@ -84,7 +82,7 @@ ResourceParametersField = Field(
VALID_INPUTS_BY_ITEMS = ["step_id", "step_index", "step_uuid", "name"]
-def validateInputsBy(inputsBy: Optional[str]) -> Optional[str]:
+def validateInputsBy(inputsBy: str | None) -> str | None:
if inputsBy is not None:
if not isinstance(inputsBy, str):
raise ValueError(f"Invalid type for inputsBy {inputsBy}")
@@ -100,14 +98,14 @@ InputsByValidator = AfterValidator(validateInputsBy)
class GetTargetHistoryPayload(Model):
# TODO - Are the descriptions correct?
- history: Optional[str] = Field(
+ history: str | None = Field(
None,
title="History",
# description="The encoded history id - passed exactly like this 'hist_id=...' - to import the workflow into. Or the name of the new history to import the workflow into.",
description="The encoded history id - passed exactly like this 'hist_id=...' - into which to import. Or the name of the new history into which to import.",
)
- history_id: Optional[str] = TargetHistoryIdField
- new_history_name: Optional[str] = Field(
+ history_id: str | None = TargetHistoryIdField
+ new_history_name: str | None = Field(
None,
title="New History Name",
# description="The name of the new history to import the workflow into.",
@@ -117,49 +115,49 @@ class GetTargetHistoryPayload(Model):
class InvokeWorkflowPayload(GetTargetHistoryPayload):
# TODO - Are the descriptions correct?
- version: Optional[int] = Field(
+ version: int | None = Field(
None,
title="Version",
description="The version of the workflow to invoke.",
)
- instance: Optional[bool] = Field(
+ instance: bool | None = Field(
False,
title="Is instance",
description="True when fetching by Workflow ID, False when fetching by StoredWorkflow ID",
)
- scheduler: Optional[str] = Field(
+ scheduler: str | None = Field(
None,
title="Scheduler",
description="Scheduler to use for workflow invocation.",
)
- batch: Optional[bool] = Field(
+ batch: bool | None = Field(
False,
title="Batch",
description="Indicates if the workflow is invoked as a batch.",
)
- require_exact_tool_versions: Optional[bool] = Field(
+ require_exact_tool_versions: bool | None = Field(
True,
title="Require Exact Tool Versions",
description="If true, exact tool versions are required for workflow invocation.",
# description="TODO",
)
- allow_tool_state_corrections: Optional[bool] = Field(
+ allow_tool_state_corrections: bool | None = Field(
False,
title="Allow tool state corrections",
description="Indicates if tool state corrections are allowed for workflow invocation.",
)
- landing_uuid: Optional[UUID4] = Field(
+ landing_uuid: UUID4 | None = Field(
None,
title="Landing UUID",
description="The UUID of the workflow landing request associated with this invocation.",
)
- use_cached_job: Optional[bool] = UseCachedJobField
- parameters_normalized: Optional[bool] = Field(
+ use_cached_job: bool | None = UseCachedJobField
+ parameters_normalized: bool | None = Field(
False,
title=STEP_PARAMETERS_NORMALIZED_TITLE,
description=STEP_PARAMETERS_NORMALIZED_DESCRIPTION,
)
- on_complete: Optional[list[dict[str, Any]]] = Field(
+ on_complete: list[dict[str, Any]] | None = Field(
None,
title="On Complete Actions",
description=(
@@ -187,54 +185,54 @@ class InvokeWorkflowPayload(GetTargetHistoryPayload):
return json.loads(v)
return v
- parameters: Optional[dict[str, dict[str, Any]]] = Field(
+ parameters: dict[str, dict[str, Any]] | None = Field(
{},
title=STEP_PARAMETERS_TITLE,
description=STEP_PARAMETERS_DESCRIPTION,
)
- inputs: Optional[dict[str, Any]] = Field(
+ inputs: dict[str, Any] | None = Field(
None,
title="Inputs",
description="Specify values for formal inputs to the workflow",
)
- ds_map: Optional[dict[str, dict[str, Any]]] = Field(
+ ds_map: dict[str, dict[str, Any]] | None = Field(
{},
title="Legacy Dataset Map",
description="An older alternative to specifying inputs using database IDs, do not use this and use inputs instead",
deprecated=True,
)
- resource_params: Optional[dict[str, Any]] = ResourceParametersField
- replacement_params: Optional[dict[str, Any]] = ReplacementParametersField
- no_add_to_history: Optional[bool] = Field(
+ resource_params: dict[str, Any] | None = ResourceParametersField
+ replacement_params: dict[str, Any] | None = ReplacementParametersField
+ no_add_to_history: bool | None = Field(
False,
title="No Add to History",
description="Indicates if the workflow invocation should not be added to the history.",
)
- legacy: Optional[bool] = Field(
+ legacy: bool | None = Field(
False,
title="Legacy",
description="Indicating if to use legacy workflow invocation.",
)
- inputs_by: Annotated[Optional[str], InputsByValidator] = Field(
+ inputs_by: Annotated[str | None, InputsByValidator] = Field(
None,
title="Inputs By",
# lib/galaxy/workflow/run_request.py - see line 60
description=INPUTS_BY_DESCRIPTION,
)
- effective_outputs: Optional[Any] = Field(
+ effective_outputs: Any | None = Field(
None,
title="Effective Outputs",
# lib/galaxy/workflow/run_request.py - see line 455
description="TODO",
)
- preferred_object_store_id: Optional[str] = PreferredObjectStoreIdField
- preferred_intermediate_object_store_id: Optional[str] = PreferredIntermediateObjectStoreIdField
- preferred_outputs_object_store_id: Optional[str] = PreferredOutputsObjectStoreIdField
+ preferred_object_store_id: str | None = PreferredObjectStoreIdField
+ preferred_intermediate_object_store_id: str | None = PreferredIntermediateObjectStoreIdField
+ preferred_outputs_object_store_id: str | None = PreferredOutputsObjectStoreIdField
class StoredWorkflowDetailed(StoredWorkflowSummary):
- annotation: Optional[str] = AnnotationField # Inconsistency? See comment on StoredWorkflowSummary.annotations
- license: Optional[str] = Field(
+ annotation: str | None = AnnotationField # Inconsistency? See comment on StoredWorkflowSummary.annotations
+ license: str | None = Field(
None, title="License", description="SPDX Identifier of the license associated with this workflow."
)
version: int = Field(
@@ -243,7 +241,7 @@ class StoredWorkflowDetailed(StoredWorkflowSummary):
inputs: dict[int, WorkflowInput] = Field(
{}, title="Inputs", description="A dictionary containing information about all the inputs of the workflow."
)
- creator: Optional[list[Union[Person, CreatorOrganization]]] = Field(
+ creator: list[Person | CreatorOrganization] | None = Field(
None,
title="Creator",
description=("Additional information about the creator (or multiple creators) of this workflow."),
@@ -253,20 +251,13 @@ class StoredWorkflowDetailed(StoredWorkflowSummary):
title="Creator deleted",
description="Whether the creator of this Workflow has been deleted.",
)
- doi: Optional[list[str]] = Field(
+ doi: list[str] | None = Field(
None, title="DOI", description="A list of Digital Object Identifiers associated with this workflow."
)
steps: dict[
int,
Annotated[
- Union[
- InputDataStep,
- InputDataCollectionStep,
- InputParameterStep,
- PauseStep,
- ToolStep,
- SubworkflowStep,
- ],
+ InputDataStep | InputDataCollectionStep | InputParameterStep | PauseStep | ToolStep | SubworkflowStep,
Field(discriminator="type"),
],
] = Field(
@@ -274,32 +265,32 @@ class StoredWorkflowDetailed(StoredWorkflowSummary):
title="Steps",
description="A dictionary with information about all the steps of the workflow.",
)
- importable: Optional[bool] = Field(
+ importable: bool | None = Field(
...,
title="Importable",
description="Indicates if the workflow is importable by the current user.",
)
- email_hash: Optional[str] = Field(
+ email_hash: str | None = Field(
...,
title="Email Hash",
description="The hash of the email of the creator of this workflow",
)
- readme: Optional[str] = Field(
+ readme: str | None = Field(
...,
title="Readme",
description="The detailed markdown readme of the workflow.",
)
- help: Optional[str] = Field(
+ help: str | None = Field(
...,
title="Help",
description="The detailed help text for how to use the workflow and debug problems with it.",
)
- slug: Optional[str] = Field(
+ slug: str | None = Field(
...,
title="Slug",
description="The slug of the workflow.",
)
- source_metadata: Optional[dict[str, Any]] = Field(
+ source_metadata: dict[str, Any] | None = Field(
...,
title="Source Metadata",
description="The source metadata of the workflow.",
@@ -337,17 +328,17 @@ class WorkflowExtractionOutput(Model):
title="History Content Type",
description="Whether this is a dataset or dataset_collection.",
)
- output_name: Optional[str] = Field(
+ output_name: str | None = Field(
None,
title="Output Name",
description="Workflow/tool output port name for this concrete output, when known.",
)
- suggested_name: Optional[str] = Field(
+ suggested_name: str | None = Field(
None,
title="Suggested Name",
description="Suggested workflow output label for this concrete output.",
)
- suggested_name_source: Optional[Literal["renamed", "rendered_label", "bare_label", "port_name"]] = Field(
+ suggested_name_source: Literal["renamed", "rendered_label", "bare_label", "port_name"] | None = Field(
None,
title="Suggested Name Source",
description="Source used to derive the suggested workflow output label.",
@@ -385,7 +376,7 @@ class InvalidWorkflowExtractionJobReason(str, Enum):
class WorkflowExtractionJob(Model):
- id: Optional[EncodedDatabaseIdField] = Field(
+ id: EncodedDatabaseIdField | None = Field(
...,
title="ID",
description="Encoded job ID, or null for fake input dataset entries.",
@@ -395,17 +386,17 @@ class WorkflowExtractionJob(Model):
title="Step Type",
description="The role this job plays in the extracted workflow.",
)
- tool_id: Optional[str] = Field(
+ tool_id: str | None = Field(
None,
title="Tool ID",
description="The tool ID that created this job.",
)
- tool_name: Optional[str] = Field(
+ tool_name: str | None = Field(
None,
title="Tool Name",
description="Human-readable name of the tool.",
)
- tool_version: Optional[str] = Field(
+ tool_version: str | None = Field(
None,
title="Tool Version",
description="The tool version used by this job.",
@@ -415,7 +406,7 @@ class WorkflowExtractionJob(Model):
title="Checked",
description="Whether this job should be preselected for extraction (True if any outputs are not deleted).",
)
- tool_version_warning: Optional[str] = Field(
+ tool_version_warning: str | None = Field(
None,
title="Tool Version Warning",
description="Warning when the current tool version differs from the version used by this job.",
@@ -425,12 +416,12 @@ class WorkflowExtractionJob(Model):
title="Outputs",
description="The history items produced by this job.",
)
- invalid: Optional[InvalidWorkflowExtractionJobReason] = Field(
+ invalid: InvalidWorkflowExtractionJobReason | None = Field(
None,
title="Invalid",
description="Reason this job is invalid for extraction.",
)
- implicit_collection_jobs_id: Optional[EncodedDatabaseIdField] = Field(
+ implicit_collection_jobs_id: EncodedDatabaseIdField | None = Field(
None,
title="Implicit Collection Jobs ID",
description=(
@@ -440,7 +431,7 @@ class WorkflowExtractionJob(Model):
"rather than job_ids in the extract-by-ids payload."
),
)
- implicit_collection_jobs_size: Optional[int] = Field(
+ implicit_collection_jobs_size: int | None = Field(
None,
title="Implicit Collection Jobs Size",
description="Number of constituent jobs in the ICJ (only set when implicit_collection_jobs_id is non-null).",
diff --git a/lib/galaxy/security/__init__.py b/lib/galaxy/security/__init__.py
index 401b3d535b7..63a4d5a092a 100644
--- a/lib/galaxy/security/__init__.py
+++ b/lib/galaxy/security/__init__.py
@@ -5,7 +5,6 @@ Galaxy Security
from typing import (
Literal,
- Optional,
)
from galaxy.util.bunch import Bunch
@@ -54,7 +53,7 @@ class RBACAgent:
),
)
- def get_action(self, name: str, default: Optional[Action] = None) -> Optional[Action]:
+ def get_action(self, name: str, default: Action | None = None) -> Action | None:
"""Get a permitted action by its dict key or action name"""
for k, v in self.permitted_actions.items():
if k == name or v.action == name:
diff --git a/lib/galaxy/security/idencoding.py b/lib/galaxy/security/idencoding.py
index e1eca5d2a31..246be710f30 100644
--- a/lib/galaxy/security/idencoding.py
+++ b/lib/galaxy/security/idencoding.py
@@ -1,10 +1,6 @@
import codecs
import collections
import logging
-from typing import (
- Optional,
- Union,
-)
from Crypto.Cipher import Blowfish
from Crypto.Random import get_random_bytes
@@ -88,7 +84,7 @@ class IdEncodingHelper:
rval[k] = [self.encode_all_ids(el, True) for el in v]
return rval
- def decode_id(self, obj_id, kind=None, object_name: Optional[str] = None):
+ def decode_id(self, obj_id, kind=None, object_name: str | None = None):
try:
id_cipher = self.__id_cipher(kind)
return int(unicodify(id_cipher.decrypt(codecs.decode(obj_id, "hex"))).lstrip("!"))
@@ -109,7 +105,7 @@ class IdEncodingHelper:
# Encrypt
return codecs.encode(self.id_cipher.encrypt(s), "hex")
- def decode_guid(self, session_key: Union[bytes, str]) -> str:
+ def decode_guid(self, session_key: bytes | str) -> str:
# Session keys are strings
try:
decoded_session_key = codecs.decode(session_key, "hex")
diff --git a/lib/galaxy/security/validate_user_input.py b/lib/galaxy/security/validate_user_input.py
index c8660a96ef0..4d827baf6ff 100644
--- a/lib/galaxy/security/validate_user_input.py
+++ b/lib/galaxy/security/validate_user_input.py
@@ -7,9 +7,6 @@ user inputs - so these methods do not need to be escaped.
import logging
import re
-from typing import (
- Optional,
-)
import dns.resolver
from dns.exception import DNSException
@@ -174,13 +171,11 @@ def validate_password(trans, password, confirm):
return validate_password_str(password)
-def validate_preferred_object_store_id(
- trans, object_store: ObjectStore, preferred_object_store_id: Optional[str]
-) -> str:
+def validate_preferred_object_store_id(trans, object_store: ObjectStore, preferred_object_store_id: str | None) -> str:
return object_store.validate_selected_object_store_id(trans.user, preferred_object_store_id) or ""
-def is_email_banned(email: str, filepath: Optional[str], canonical_email_rules: Optional[dict]) -> bool:
+def is_email_banned(email: str, filepath: str | None, canonical_email_rules: dict | None) -> bool:
if not filepath:
return False
normalizer = EmailAddressNormalizer(canonical_email_rules)
@@ -205,7 +200,7 @@ class EmailAddressNormalizer:
SUB_ADDRESSING_DELIM_DEFAULT = "+"
ALL = "all"
- def __init__(self, canonical_email_rules: Optional[dict]) -> None:
+ def __init__(self, canonical_email_rules: dict | None) -> None:
self.config = canonical_email_rules
def normalize(self, email: str) -> str:
diff --git a/lib/galaxy/security/vault.py b/lib/galaxy/security/vault.py
index a3ed91b2802..fc7011fc688 100644
--- a/lib/galaxy/security/vault.py
+++ b/lib/galaxy/security/vault.py
@@ -2,9 +2,6 @@ import abc
import logging
import os
import re
-from typing import (
- Optional,
-)
import yaml
from cryptography.fernet import (
@@ -45,7 +42,7 @@ class Vault(abc.ABC):
use_canonical_keys = True
@abc.abstractmethod
- def read_secret(self, key: str) -> Optional[str]:
+ def read_secret(self, key: str) -> str | None:
"""
Reads a secret from the vault.
@@ -89,7 +86,7 @@ class Vault(abc.ABC):
class NullVault(Vault):
- def read_secret(self, key: str) -> Optional[str]:
+ def read_secret(self, key: str) -> str | None:
raise InvalidVaultConfigException(
"No vault configured. Make sure the vault_config_file setting is defined in galaxy.yml"
)
@@ -142,13 +139,12 @@ class HashicorpVault(Vault):
renewable = auth_data.get("renewable", False)
if not renewable:
log.error(
- "Hashicorp Vault token is no longer renewable (max TTL likely reached). "
- "A new token must be configured."
+ "Hashicorp Vault token is no longer renewable (max TTL likely reached). A new token must be configured."
)
else:
log.debug("Hashicorp Vault token renewed successfully (new TTL: %ds).", new_ttl)
- def read_secret(self, key: str) -> Optional[str]:
+ def read_secret(self, key: str) -> str | None:
try:
response = self.client.secrets.kv.read_secret_version(path=key)
return response["data"]["data"].get("value")
@@ -162,7 +158,7 @@ class HashicorpVault(Vault):
)
return None
- def _read_legacy_and_migrate(self, key: str) -> Optional[str]:
+ def _read_legacy_and_migrate(self, key: str) -> str | None:
# Galaxy <= 26.0 emitted a leading slash in Vault paths, which hvac's
# format_url turned into a double-slash KV v2 key. Vault 1.x accepted
# it silently; Vault 2.0 rejects it. Fall back to reading the legacy
@@ -207,7 +203,7 @@ class DatabaseVault(Vault):
def _get_multi_fernet(self) -> MultiFernet:
return MultiFernet(self.fernet_keys)
- def _update_or_create(self, key: str, value: Optional[str]) -> model.Vault:
+ def _update_or_create(self, key: str, value: str | None) -> model.Vault:
vault_entry = self._get_vault_value(key)
if vault_entry:
if value:
@@ -224,7 +220,7 @@ class DatabaseVault(Vault):
self.sa_session.commit()
return vault_entry
- def read_secret(self, key: str) -> Optional[str]:
+ def read_secret(self, key: str) -> str | None:
key_obj = self._get_vault_value(key)
if key_obj and key_obj.value:
f = self._get_multi_fernet()
@@ -254,7 +250,7 @@ class UserVaultWrapper(Vault):
self.vault = vault
self.user = user
- def read_secret(self, key: str) -> Optional[str]:
+ def read_secret(self, key: str) -> str | None:
if self.user:
return self.vault.read_secret(f"user/{self.user.id}/{key}")
else:
@@ -291,7 +287,7 @@ class VaultKeyValidationWrapper(Vault):
)
return key
- def read_secret(self, key: str) -> Optional[str]:
+ def read_secret(self, key: str) -> str | None:
key = self.normalize_key(key)
return self.vault.read_secret(key)
@@ -327,7 +323,7 @@ class VaultKeyPrefixWrapper(Vault):
return f"{self.prefix}/{key}"
return f"/{self.prefix}/{key}"
- def read_secret(self, key: str) -> Optional[str]:
+ def read_secret(self, key: str) -> str | None:
return self.vault.read_secret(self._prefixed(key))
def write_secret(self, key: str, value: str) -> None:
@@ -339,14 +335,14 @@ class VaultKeyPrefixWrapper(Vault):
class VaultFactory:
@staticmethod
- def load_vault_config(vault_conf_yml: str) -> Optional[dict]:
+ def load_vault_config(vault_conf_yml: str) -> dict | None:
if os.path.exists(vault_conf_yml):
with open(vault_conf_yml) as f:
return yaml.safe_load(f)
return None
@staticmethod
- def from_vault_type(app, vault_type: Optional[str], cfg: dict) -> Vault:
+ def from_vault_type(app, vault_type: str | None, cfg: dict) -> Vault:
vault: Vault
if vault_type == "hashicorp":
token_renewal_enabled = app.config.vault_token_renewal_interval > 0
diff --git a/lib/galaxy/selenium/axe_results.py b/lib/galaxy/selenium/axe_results.py
index a43e1d61c6a..59d5d425347 100644
--- a/lib/galaxy/selenium/axe_results.py
+++ b/lib/galaxy/selenium/axe_results.py
@@ -1,7 +1,6 @@
from typing import (
Any,
Literal,
- Optional,
)
from typing_extensions import (
@@ -46,7 +45,7 @@ class AxeResult:
return self._json["description"]
@property
- def impact(self) -> Optional[Impact]:
+ def impact(self) -> Impact | None:
return self._json["impact"]
@property
@@ -88,9 +87,7 @@ class AxeResults(Protocol):
def violations_with_impact_of_at_least(self, impact: Impact) -> list[Violation]:
""""""
- def assert_no_violations_with_impact_of_at_least(
- self, impact: Impact, excludes: Optional[list[str]] = None
- ) -> None:
+ def assert_no_violations_with_impact_of_at_least(self, impact: Impact, excludes: list[str] | None = None) -> None:
""""""
@@ -116,9 +113,7 @@ class RealAxeResults(AxeResults):
def violations_with_impact_of_at_least(self, impact: Impact) -> list[Violation]:
return [v for v in self.violations() if v.is_impact_at_least(impact)]
- def assert_no_violations_with_impact_of_at_least(
- self, impact: Impact, excludes: Optional[list[str]] = None
- ) -> None:
+ def assert_no_violations_with_impact_of_at_least(self, impact: Impact, excludes: list[str] | None = None) -> None:
excludes = excludes or []
violations = self.violations_with_impact_of_at_least(impact)
filtered_violations = [v for v in violations if v.id not in excludes]
@@ -142,9 +137,7 @@ class NullAxeResults(AxeResults):
def violations_with_impact_of_at_least(self, impact: Impact) -> list[Violation]:
return []
- def assert_no_violations_with_impact_of_at_least(
- self, impact: Impact, excludes: Optional[list[str]] = None
- ) -> None:
+ def assert_no_violations_with_impact_of_at_least(self, impact: Impact, excludes: list[str] | None = None) -> None:
pass
@@ -157,7 +150,7 @@ def assert_baseline_accessible(axe_results: AxeResults) -> None:
raise AssertionError(violation.message)
-def _check_list_for_id(result_list: list[dict[str, Any]], id) -> Optional[dict[str, Any]]:
+def _check_list_for_id(result_list: list[dict[str, Any]], id) -> dict[str, Any] | None:
for result in result_list:
if result.get("id") == id:
return result
diff --git a/lib/galaxy/selenium/context.py b/lib/galaxy/selenium/context.py
index b6996fa160f..8102f41b612 100644
--- a/lib/galaxy/selenium/context.py
+++ b/lib/galaxy/selenium/context.py
@@ -1,6 +1,5 @@
import os
from abc import abstractmethod
-from typing import Optional
from urllib.parse import urljoin
import yaml
@@ -47,7 +46,7 @@ class GalaxySeleniumContext(NavigatesGalaxy):
return target
@abstractmethod
- def _screenshot_path(self, label: str, extension=".png") -> Optional[str]:
+ def _screenshot_path(self, label: str, extension=".png") -> str | None:
"""Path to store screenshots in."""
@@ -58,7 +57,7 @@ class GalaxySeleniumContextImpl(GalaxySeleniumContext):
to then interact with via the Selenium is :class:`galaxy_test.selenium.framework.GalaxySeleniumContextImpl`.
"""
- def __init__(self, from_dict: Optional[dict] = None) -> None:
+ def __init__(self, from_dict: dict | None = None) -> None:
from_dict = from_dict or {}
self.configured_driver = ConfiguredDriver(**from_dict.get("driver", {}))
self.url = from_dict.get("local_galaxy_url", "http://localhost:8080")
diff --git a/lib/galaxy/selenium/driver_factory.py b/lib/galaxy/selenium/driver_factory.py
index ab6373705ff..471a8600afc 100644
--- a/lib/galaxy/selenium/driver_factory.py
+++ b/lib/galaxy/selenium/driver_factory.py
@@ -4,7 +4,6 @@ from typing import (
Any,
cast,
Literal,
- Union,
)
# Playwright browser type names (matches BrowserType.name property)
@@ -303,7 +302,7 @@ def get_playwright_driver(browser: str = DEFAULT_BROWSER, headless: bool = False
def get_remote_driver(host, port, browser=DEFAULT_BROWSER) -> WebDriver:
# docker run -d -p 4444:4444 -v /dev/shm:/dev/shm selenium/standalone-chrome:3.0.1-aluminum
- options: Union[webdriver.ChromeOptions, webdriver.FirefoxOptions, webdriver.EdgeOptions, SafariOptions]
+ options: webdriver.ChromeOptions | webdriver.FirefoxOptions | webdriver.EdgeOptions | SafariOptions
if browser == "auto" or browser == "CHROME":
options = webdriver.ChromeOptions()
options.set_capability("goog:loggingPrefs", LOGGING_PREFS)
diff --git a/lib/galaxy/selenium/has_driver.py b/lib/galaxy/selenium/has_driver.py
index 88b6bc5b360..c5904e4c5ed 100644
--- a/lib/galaxy/selenium/has_driver.py
+++ b/lib/galaxy/selenium/has_driver.py
@@ -12,8 +12,6 @@ from typing import (
cast,
Generic,
Literal,
- Optional,
- Union,
)
from axe_selenium_python import Axe
@@ -49,7 +47,7 @@ from .web_element_protocol import WebElementProtocol
UNSPECIFIED_TIMEOUT = object()
-HasFindElement = Union[WebDriver, WebElement]
+HasFindElement = WebDriver | WebElement
DEFAULT_AXE_SCRIPT_URL = "https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.7.1/axe.min.js"
AXE_SCRIPT_HASH: dict[str, str] = {}
AXE_SCRIPT_HASH_LOCK = threading.Lock()
@@ -249,7 +247,7 @@ class HasDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTypeT]):
def element_absent(self, selector_template: Target) -> bool:
return len(self.find_elements(selector_template)) == 0
- def switch_to_frame(self, frame_reference: Union[str, int, WebElement] = "frame"):
+ def switch_to_frame(self, frame_reference: str | int | WebElement = "frame"):
"""
Switch to an iframe or frame.
@@ -329,7 +327,7 @@ class HasDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTypeT]):
element = self.driver.find_element(*selector_template.element_locator)
element.click()
- def _wait_on_selenium_condition(self, condition, on_str: Optional[str] = None, **kwds):
+ def _wait_on_selenium_condition(self, condition, on_str: str | None = None, **kwds):
if on_str is None:
on_str = str(condition)
wait = self.wait(**kwds)
@@ -370,13 +368,13 @@ class HasDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTypeT]):
"""
self.action_chains().move_to_element(element).perform()
- def send_enter(self, element: Optional[WebElement] = None):
+ def send_enter(self, element: WebElement | None = None):
self._send_key(Keys.ENTER, element)
- def send_escape(self, element: Optional[WebElement] = None):
+ def send_escape(self, element: WebElement | None = None):
self._send_key(Keys.ESCAPE, element)
- def send_backspace(self, element: Optional[WebElement] = None):
+ def send_backspace(self, element: WebElement | None = None):
self._send_key(Keys.BACKSPACE, element)
def aggressive_clear(self, element: WebElement) -> None:
@@ -385,7 +383,7 @@ class HasDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTypeT]):
for _ in range(25):
element.send_keys(Keys.BACKSPACE)
- def _send_key(self, key: str, element: Optional[WebElement] = None):
+ def _send_key(self, key: str, element: WebElement | None = None):
if element is None:
self.action_chains().send_keys(key)
else:
@@ -397,7 +395,7 @@ class HasDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTypeT]):
"""Get timeout handler for application specific wait types."""
...
- def wait(self, timeout=UNSPECIFIED_TIMEOUT, wait_type: Optional[WaitTypeT] = None, **kwds):
+ def wait(self, timeout=UNSPECIFIED_TIMEOUT, wait_type: WaitTypeT | None = None, **kwds):
if timeout is UNSPECIFIED_TIMEOUT:
timeout = self.timeout_handler(wait_type)
return WebDriverWait(self.driver, timeout)
@@ -478,7 +476,7 @@ class HasDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTypeT]):
"""
return self.driver.execute_script(script, *args)
- def set_local_storage(self, key: str, value: Union[str, float]) -> None:
+ def set_local_storage(self, key: str, value: str | float) -> None:
"""
Set a value in the browser's localStorage.
@@ -529,21 +527,19 @@ class HasDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTypeT]):
"""
self.execute_script("arguments[0].click();", element)
- def find_element_by_link_text(self, text: str, element: Optional[WebElement] = None) -> WebElementProtocol:
+ def find_element_by_link_text(self, text: str, element: WebElement | None = None) -> WebElementProtocol:
return _webelement_to_protocol(self._locator_aware(element).find_element(By.LINK_TEXT, text))
- def find_element_by_xpath(self, xpath: str, element: Optional[WebElement] = None) -> WebElementProtocol:
+ def find_element_by_xpath(self, xpath: str, element: WebElement | None = None) -> WebElementProtocol:
return _webelement_to_protocol(self._locator_aware(element).find_element(By.XPATH, xpath))
- def find_element_by_id(self, id: str, element: Optional[WebElement] = None) -> WebElementProtocol:
+ def find_element_by_id(self, id: str, element: WebElement | None = None) -> WebElementProtocol:
return _webelement_to_protocol(self._locator_aware(element).find_element(By.ID, id))
- def find_element_by_selector(self, selector: str, element: Optional[WebElement] = None) -> WebElementProtocol:
+ def find_element_by_selector(self, selector: str, element: WebElement | None = None) -> WebElementProtocol:
return _webelement_to_protocol(self._locator_aware(element).find_element(By.CSS_SELECTOR, selector))
- def find_elements_by_selector(
- self, selector: str, element: Optional[WebElement] = None
- ) -> list[WebElementProtocol]:
+ def find_elements_by_selector(self, selector: str, element: WebElement | None = None) -> list[WebElementProtocol]:
"""
Find multiple elements by CSS selector.
@@ -591,7 +587,7 @@ class HasDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTypeT]):
select = Select(select_element)
select.select_by_value(value)
- def axe_eval(self, context: Optional[str] = None, write_to: Optional[str] = None) -> AxeResults:
+ def axe_eval(self, context: str | None = None, write_to: str | None = None) -> AxeResults:
if self.axe_skip:
return NullAxeResults()
@@ -634,7 +630,7 @@ class HasDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTypeT]):
"""
self.driver.quit()
- def _locator_aware(self, element: Optional[WebElement] = None) -> HasFindElement:
+ def _locator_aware(self, element: WebElement | None = None) -> HasFindElement:
if element is None:
return self.driver
else:
diff --git a/lib/galaxy/selenium/has_driver_protocol.py b/lib/galaxy/selenium/has_driver_protocol.py
index 0c168ff7451..ed2d8b42eeb 100644
--- a/lib/galaxy/selenium/has_driver_protocol.py
+++ b/lib/galaxy/selenium/has_driver_protocol.py
@@ -11,11 +11,9 @@ from typing import (
Any,
Generic,
Literal,
- Optional,
Protocol,
TypedDict,
TypeVar,
- Union,
)
from galaxy.navigation.components import Target
@@ -24,7 +22,7 @@ from .web_element_protocol import WebElementProtocol
# Type for element locators - can be either a Target or a Selenium-style (locator_type, value) tuple
ElementLocatorTuple = tuple[str, str] # e.g., ("css selector", "#id") or ("id", "test")
-HasElementLocator = Union[Target, ElementLocatorTuple]
+HasElementLocator = Target | ElementLocatorTuple
class Cookie(TypedDict, total=False):
@@ -42,7 +40,7 @@ class Cookie(TypedDict, total=False):
BackendType = Literal["selenium", "playwright"]
WaitTypeT = TypeVar("WaitTypeT", contravariant=True)
-TimeoutCallback = Callable[[Optional[WaitTypeT]], float]
+TimeoutCallback = Callable[[WaitTypeT | None], float]
def fixed_timeout_handler(timeout: float) -> TimeoutCallback:
@@ -89,7 +87,7 @@ class HasDriverProtocol(Protocol, Generic[WaitTypeT]):
...
@abstractmethod
- def wait(self, timeout=..., wait_type: Optional[WaitTypeT] = None, **kwds):
+ def wait(self, timeout=..., wait_type: WaitTypeT | None = None, **kwds):
"""Create a wait object with the specified timeout."""
...
@@ -129,27 +127,27 @@ class HasDriverProtocol(Protocol, Generic[WaitTypeT]):
# Element finding - by locator type
@abstractmethod
- def find_element_by_id(self, id: str, element: Optional[Any] = None) -> WebElementProtocol:
+ def find_element_by_id(self, id: str, element: Any | None = None) -> WebElementProtocol:
"""Find element by ID attribute."""
...
@abstractmethod
- def find_element_by_selector(self, selector: str, element: Optional[Any] = None) -> WebElementProtocol:
+ def find_element_by_selector(self, selector: str, element: Any | None = None) -> WebElementProtocol:
"""Find element by CSS selector."""
...
@abstractmethod
- def find_element_by_xpath(self, xpath: str, element: Optional[Any] = None) -> WebElementProtocol:
+ def find_element_by_xpath(self, xpath: str, element: Any | None = None) -> WebElementProtocol:
"""Find element by XPath expression."""
...
@abstractmethod
- def find_element_by_link_text(self, text: str, element: Optional[Any] = None) -> WebElementProtocol:
+ def find_element_by_link_text(self, text: str, element: Any | None = None) -> WebElementProtocol:
"""Find link element by visible text."""
...
@abstractmethod
- def find_elements_by_selector(self, selector: str, element: Optional[Any] = None) -> list[WebElementProtocol]:
+ def find_elements_by_selector(self, selector: str, element: Any | None = None) -> list[WebElementProtocol]:
"""Find all elements matching CSS selector."""
...
@@ -370,17 +368,17 @@ class HasDriverProtocol(Protocol, Generic[WaitTypeT]):
# Keyboard interactions
@abstractmethod
- def send_enter(self, element: Optional[WebElementProtocol] = None):
+ def send_enter(self, element: WebElementProtocol | None = None):
"""Send ENTER key to element or active element."""
...
@abstractmethod
- def send_escape(self, element: Optional[WebElementProtocol] = None):
+ def send_escape(self, element: WebElementProtocol | None = None):
"""Send ESCAPE key to element or active element."""
...
@abstractmethod
- def send_backspace(self, element: Optional[WebElementProtocol] = None):
+ def send_backspace(self, element: WebElementProtocol | None = None):
"""Send BACKSPACE key to element or active element."""
...
@@ -429,7 +427,7 @@ class HasDriverProtocol(Protocol, Generic[WaitTypeT]):
# Frame switching
@abstractmethod
- def switch_to_frame(self, frame_reference: Union[str, int, Any] = "frame"):
+ def switch_to_frame(self, frame_reference: str | int | Any = "frame"):
"""Switch to iframe by name, id, index, or element."""
...
@@ -461,7 +459,7 @@ class HasDriverProtocol(Protocol, Generic[WaitTypeT]):
# Storage and cookies
@abstractmethod
- def set_local_storage(self, key: str, value: Union[str, float]) -> None:
+ def set_local_storage(self, key: str, value: str | float) -> None:
"""Set localStorage item."""
...
@@ -490,7 +488,7 @@ class HasDriverProtocol(Protocol, Generic[WaitTypeT]):
# Accessibility
@abstractmethod
- def axe_eval(self, context: Optional[str] = None, write_to: Optional[str] = None) -> AxeResults:
+ def axe_eval(self, context: str | None = None, write_to: str | None = None) -> AxeResults:
"""Run axe-core accessibility tests."""
...
diff --git a/lib/galaxy/selenium/has_driver_proxy.py b/lib/galaxy/selenium/has_driver_proxy.py
index 37fc278d6f2..921ef90b40f 100644
--- a/lib/galaxy/selenium/has_driver_proxy.py
+++ b/lib/galaxy/selenium/has_driver_proxy.py
@@ -13,8 +13,6 @@ from abc import (
from typing import (
Any,
Generic,
- Optional,
- Union,
)
from galaxy.navigation.components import Target
@@ -83,7 +81,7 @@ class HasDriverProxy(ABC, Generic[WaitTypeT]):
"""Get timeout handler for application specific wait types."""
return self._driver_impl.timeout_handler
- def wait(self, timeout=..., wait_type: Optional[WaitTypeT] = None, **kwds):
+ def wait(self, timeout=..., wait_type: WaitTypeT | None = None, **kwds):
"""Create a wait object with the specified timeout."""
return self._driver_impl.wait(timeout, wait_type=wait_type, **kwds)
@@ -118,23 +116,23 @@ class HasDriverProxy(ABC, Generic[WaitTypeT]):
# Element finding - by locator type
- def find_element_by_id(self, id: str, element: Optional[Any] = None) -> WebElementProtocol:
+ def find_element_by_id(self, id: str, element: Any | None = None) -> WebElementProtocol:
"""Find element by ID attribute."""
return self._driver_impl.find_element_by_id(id, element)
- def find_element_by_selector(self, selector: str, element: Optional[Any] = None) -> WebElementProtocol:
+ def find_element_by_selector(self, selector: str, element: Any | None = None) -> WebElementProtocol:
"""Find element by CSS selector."""
return self._driver_impl.find_element_by_selector(selector, element)
- def find_element_by_xpath(self, xpath: str, element: Optional[Any] = None) -> WebElementProtocol:
+ def find_element_by_xpath(self, xpath: str, element: Any | None = None) -> WebElementProtocol:
"""Find element by XPath expression."""
return self._driver_impl.find_element_by_xpath(xpath, element)
- def find_element_by_link_text(self, text: str, element: Optional[Any] = None) -> WebElementProtocol:
+ def find_element_by_link_text(self, text: str, element: Any | None = None) -> WebElementProtocol:
"""Find link element by visible text."""
return self._driver_impl.find_element_by_link_text(text, element)
- def find_elements_by_selector(self, selector: str, element: Optional[Any] = None) -> list[WebElementProtocol]:
+ def find_elements_by_selector(self, selector: str, element: Any | None = None) -> list[WebElementProtocol]:
"""Find all elements matching CSS selector."""
return self._driver_impl.find_elements_by_selector(selector, element)
@@ -326,15 +324,15 @@ class HasDriverProxy(ABC, Generic[WaitTypeT]):
# Keyboard interactions
- def send_enter(self, element: Optional[WebElementProtocol] = None):
+ def send_enter(self, element: WebElementProtocol | None = None):
"""Send ENTER key to element or active element."""
return self._driver_impl.send_enter(element)
- def send_escape(self, element: Optional[WebElementProtocol] = None):
+ def send_escape(self, element: WebElementProtocol | None = None):
"""Send ESCAPE key to element or active element."""
return self._driver_impl.send_escape(element)
- def send_backspace(self, element: Optional[WebElementProtocol] = None):
+ def send_backspace(self, element: WebElementProtocol | None = None):
"""Send BACKSPACE key to element or active element."""
return self._driver_impl.send_backspace(element)
@@ -379,7 +377,7 @@ class HasDriverProxy(ABC, Generic[WaitTypeT]):
# Frame switching
- def switch_to_frame(self, frame_reference: Union[str, int, Any] = "frame"):
+ def switch_to_frame(self, frame_reference: str | int | Any = "frame"):
"""Switch to iframe by name, id, index, or element."""
return self._driver_impl.switch_to_frame(frame_reference)
@@ -407,7 +405,7 @@ class HasDriverProxy(ABC, Generic[WaitTypeT]):
# Storage and cookies
- def set_local_storage(self, key: str, value: Union[str, float]) -> None:
+ def set_local_storage(self, key: str, value: str | float) -> None:
"""Set localStorage item."""
self._driver_impl.set_local_storage(key, value)
@@ -427,7 +425,7 @@ class HasDriverProxy(ABC, Generic[WaitTypeT]):
# Accessibility
- def axe_eval(self, context: Optional[str] = None, write_to: Optional[str] = None) -> AxeResults:
+ def axe_eval(self, context: str | None = None, write_to: str | None = None) -> AxeResults:
"""Run axe-core accessibility tests."""
return self._driver_impl.axe_eval(context, write_to)
diff --git a/lib/galaxy/selenium/has_playwright_driver.py b/lib/galaxy/selenium/has_playwright_driver.py
index 93235d763ec..ce81c0102fd 100644
--- a/lib/galaxy/selenium/has_playwright_driver.py
+++ b/lib/galaxy/selenium/has_playwright_driver.py
@@ -118,8 +118,6 @@ from typing import (
Any,
Generic,
NamedTuple,
- Optional,
- Union,
)
from playwright.sync_api import (
@@ -215,7 +213,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
keys: type[PlaywrightKeys] = PlaywrightKeys
axe_script_url: str = DEFAULT_AXE_SCRIPT_URL
axe_skip: bool = False
- _current_frame: Optional[Union[Frame, FrameLocator]] = None
+ _current_frame: Frame | FrameLocator | None = None
_playwright_resources: PlaywrightResources
@property
@@ -440,7 +438,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
"""Check if element is absent."""
return len(self.find_elements(selector_template)) == 0
- def find_element_by_link_text(self, text: str, element: Optional[ElementHandle] = None) -> WebElementProtocol:
+ def find_element_by_link_text(self, text: str, element: ElementHandle | None = None) -> WebElementProtocol:
"""Find element by link text."""
if element is not None:
# Find within element context - need to use element as locator root
@@ -449,7 +447,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
element_handle = self._frame_or_page.locator(selector).first.element_handle()
return PlaywrightElement(element_handle, self)
- def find_element_by_xpath(self, xpath: str, element: Optional[ElementHandle] = None) -> WebElementProtocol:
+ def find_element_by_xpath(self, xpath: str, element: ElementHandle | None = None) -> WebElementProtocol:
"""Find element by XPath."""
if element is not None:
raise NotImplementedError("Finding within element context not yet implemented")
@@ -457,7 +455,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
element_handle = self._frame_or_page.locator(selector).first.element_handle()
return PlaywrightElement(element_handle, self)
- def find_element_by_id(self, id: str, element: Optional[ElementHandle] = None) -> WebElementProtocol:
+ def find_element_by_id(self, id: str, element: ElementHandle | None = None) -> WebElementProtocol:
"""Find element by ID."""
if element is not None:
raise NotImplementedError("Finding within element context not yet implemented")
@@ -465,7 +463,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
element_handle = self._frame_or_page.locator(selector).first.element_handle()
return PlaywrightElement(element_handle, self)
- def find_element_by_selector(self, selector: str, element: Optional[ElementHandle] = None) -> WebElementProtocol:
+ def find_element_by_selector(self, selector: str, element: ElementHandle | None = None) -> WebElementProtocol:
"""Find element by CSS selector."""
if element is not None:
raise NotImplementedError("Finding within element context not yet implemented")
@@ -473,7 +471,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
return PlaywrightElement(element_handle, self)
def find_elements_by_selector(
- self, selector: str, element: Optional[ElementHandle] = None
+ self, selector: str, element: ElementHandle | None = None
) -> list[WebElementProtocol]:
"""
Find multiple elements by CSS selector.
@@ -526,7 +524,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
selector = self._selenium_locator_to_playwright_selector(*selector_template)
self._frame_or_page.locator(selector).first.select_option(value=value)
- def _timeout_in_ms(self, timeout=UNSPECIFIED_TIMEOUT, wait_type: Optional[WaitTypeT] = None, **kwds) -> float:
+ def _timeout_in_ms(self, timeout=UNSPECIFIED_TIMEOUT, wait_type: WaitTypeT | None = None, **kwds) -> float:
"""
Convert timeout from seconds to milliseconds.
@@ -706,7 +704,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
"""
self._frame_or_page.locator(selector).first.click()
- def send_enter(self, element: Optional[WebElementProtocol] = None) -> None:
+ def send_enter(self, element: WebElementProtocol | None = None) -> None:
"""
Send ENTER key.
@@ -718,7 +716,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
else:
self._send_key_to_element(self.keys.ENTER, self._unwrap_element(element))
- def send_escape(self, element: Optional[WebElementProtocol] = None) -> None:
+ def send_escape(self, element: WebElementProtocol | None = None) -> None:
"""
Send ESCAPE key.
@@ -730,7 +728,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
else:
self._send_key_to_element(self.keys.ESCAPE, self._unwrap_element(element))
- def send_backspace(self, element: Optional[WebElementProtocol] = None) -> None:
+ def send_backspace(self, element: WebElementProtocol | None = None) -> None:
"""
Send BACKSPACE key.
@@ -844,7 +842,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
# that indicates it exists but isn't used the same way
return self
- def switch_to_frame(self, frame_reference: Union[str, int, ElementHandle, PlaywrightElement] = "frame"):
+ def switch_to_frame(self, frame_reference: str | int | ElementHandle | PlaywrightElement = "frame"):
"""
Switch to an iframe or frame.
@@ -1089,7 +1087,7 @@ class HasPlaywrightDriver(TimeoutMessageMixin, WaitMethodsMixin, Generic[WaitTyp
msg += f" {timeout_exception.message}"
return PlaywrightTimeoutException(msg)
- def axe_eval(self, context: Optional[str] = None, write_to: Optional[str] = None) -> AxeResults:
+ def axe_eval(self, context: str | None = None, write_to: str | None = None) -> AxeResults:
"""
Run axe-core accessibility tests on the current page.
diff --git a/lib/galaxy/selenium/navigates_galaxy.py b/lib/galaxy/selenium/navigates_galaxy.py
index d801a23db2b..1409c277a6d 100644
--- a/lib/galaxy/selenium/navigates_galaxy.py
+++ b/lib/galaxy/selenium/navigates_galaxy.py
@@ -22,9 +22,7 @@ from typing import (
cast,
Literal,
NamedTuple,
- Optional,
TYPE_CHECKING,
- Union,
)
import yaml
@@ -71,7 +69,7 @@ GALAXY_MAIN_FRAME_ID = "galaxy_main"
GALAXY_VISUALIZATION_FRAME_ID = "galaxy_visualization"
WaitType = collections.namedtuple("WaitType", ["name", "default_length"])
-EditorNodeReference = Union[int, str] # can reference nodes by order_index (starting at 0 as int or label)
+EditorNodeReference = int | str # can reference nodes by order_index (starting at 0 as int or label)
class HistoryEntry(NamedTuple):
@@ -105,7 +103,7 @@ class WAIT_TYPES:
def galaxy_timeout_handler(timeout_multiplier: float = 1):
- def callback(wait_type: Optional[WaitType] = None) -> float:
+ def callback(wait_type: WaitType | None = None) -> float:
if wait_type is None:
wait_type = DEFAULT_WAIT_TYPE
return wait_type.default_length * timeout_multiplier
@@ -225,7 +223,7 @@ class ConfigTemplateParameter:
class FileSourceInstance:
template_id: str
name: str
- description: Optional[str]
+ description: str | None
parameters: list[ConfigTemplateParameter] = field(default_factory=list)
@@ -233,7 +231,7 @@ class FileSourceInstance:
class ObjectStoreInstance:
template_id: str
name: str
- description: Optional[str]
+ description: str | None
parameters: list[ConfigTemplateParameter] = field(default_factory=list)
@@ -244,7 +242,7 @@ class ColumnDefinition:
# I wish these were set by value instead of by text in the text box but this is how select_set_value seems to work
type: Literal["Text", "Integer", "Element Identifier"] = "Text"
optional: bool = False
- default_value: Optional[str] = None
+ default_value: str | None = None
class NavigatesGalaxy(HasDriverProxy[WaitType]):
@@ -311,7 +309,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
def screenshot(self, label: str) -> None:
"""Take a screenshot of the current browser with the specified label."""
- def screenshot_if(self, label: Optional[str]) -> Optional[str]:
+ def screenshot_if(self, label: str | None) -> str | None:
target = None
if label:
target = self.screenshot(label)
@@ -374,7 +372,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
def wait_for_masthead(self):
self.components.masthead._.wait_for_visible()
- def go_to_workflow_landing(self, uuid: str, public: Literal["false", "true"], client_secret: Optional[str]):
+ def go_to_workflow_landing(self, uuid: str, public: Literal["false", "true"], client_secret: str | None):
path = f"workflow_landings/{uuid}?public={public}"
if client_secret:
path = f"{path}&client_secret={client_secret}"
@@ -427,7 +425,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
self.switch_to_frame(GALAXY_MAIN_FRAME_ID)
@contextlib.contextmanager
- def local_storage(self, key: str, value: Union[float, str]):
+ def local_storage(self, key: str, value: float | str):
"""Method decorator to modify localStorage for the scope of the supplied context."""
self.set_local_storage(key, value)
try:
@@ -436,7 +434,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
self.remove_local_storage(key)
@contextlib.contextmanager
- def in_frame(self, frame_reference: Union[str, int, Any] = "frame"):
+ def in_frame(self, frame_reference: str | int | Any = "frame"):
"""Context manager to operate within the context of an iframe."""
try:
self.switch_to_frame(frame_reference)
@@ -501,7 +499,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
def history_panel_name(self):
return self.history_panel_name_element().text
- def history_panel_collection_rename(self, hid: int, new_name: str, assert_old_name: Optional[str] = None):
+ def history_panel_collection_rename(self, hid: int, new_name: str, assert_old_name: str | None = None):
self.history_panel_rename(new_name)
def history_panel_expand_collection(self, collection_hid: int) -> SmartComponent:
@@ -558,7 +556,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
assert return_value, "Attempted to get latest history item on empty history."
return return_value
- def _latest_history_item(self) -> Optional[dict[str, Any]]:
+ def _latest_history_item(self) -> dict[str, Any] | None:
history_contents = self.history_contents()
if len(history_contents) > 0:
entry_dict = history_contents[-1]
@@ -609,8 +607,8 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
def _wait_on(
self,
f,
- on_str: Optional[str] = None,
- timeout: Optional[float] = None,
+ on_str: str | None = None,
+ timeout: float | None = None,
wait_type: WaitType = WAIT_TYPES.JOB_COMPLETION,
):
if timeout is None:
@@ -861,7 +859,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
search_term,
)
- def get_logged_in_user(self) -> Optional[dict[str, Any]]:
+ def get_logged_in_user(self) -> dict[str, Any] | None:
# for user's not logged in - this just returns a {} so lets
# key this on an id being available?
if "id" in (user_dict := self.api_get("users/current")):
@@ -869,7 +867,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
else:
return None
- def get_api_key(self, force=False) -> Optional[str]:
+ def get_api_key(self, force=False) -> str | None:
user_id = self.get_user_id()
if user_id is None:
if force:
@@ -882,7 +880,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
else:
return self.api_post(f"users/{user_id}/api_key")
- def get_user_id(self) -> Optional[str]:
+ def get_user_id(self) -> str | None:
if (user := self.get_logged_in_user()) is not None:
return user["id"]
else:
@@ -1505,23 +1503,23 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
def workflow_editor_add_tool_step(self, tool_id: str):
self.tool_open(tool_id)
- def workflow_editor_set_tool_vesrion(self, version: str, node: Optional[EditorNodeReference] = None) -> None:
+ def workflow_editor_set_tool_vesrion(self, version: str, node: EditorNodeReference | None = None) -> None:
editor = self.components.workflow_editor
self.workflow_editor_ensure_tool_form_open(node)
editor.tool_version_button.wait_for_and_click()
assert self.select_dropdown_item(f"Switch to {version}"), "Switch to tool version dropdown item not found"
- def workflow_editor_set_node_label(self, label: str, node: Optional[EditorNodeReference] = None):
+ def workflow_editor_set_node_label(self, label: str, node: EditorNodeReference | None = None):
self.workflow_editor_ensure_tool_form_open(node)
editor = self.components.workflow_editor
editor.label_input.wait_for_and_clear_and_send_keys(label)
- def workflow_editor_set_node_annotation(self, annotation: str, node: Optional[EditorNodeReference] = None):
+ def workflow_editor_set_node_annotation(self, annotation: str, node: EditorNodeReference | None = None):
self.workflow_editor_ensure_tool_form_open(node)
editor = self.components.workflow_editor
editor.annotation_input.wait_for_and_clear_and_send_keys(annotation)
- def workflow_editor_ensure_tool_form_open(self, node: Optional[EditorNodeReference] = None):
+ def workflow_editor_ensure_tool_form_open(self, node: EditorNodeReference | None = None):
# if node is_empty just assume current tool step is open
editor = self.components.workflow_editor
if node is not None:
@@ -1721,11 +1719,11 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
def create_quota(
self,
- name: Optional[str] = None,
- description: Optional[str] = None,
- amount: Optional[str] = None,
- quota_source_label: Optional[str] = None,
- user: Optional[str] = None,
+ name: str | None = None,
+ description: str | None = None,
+ amount: str | None = None,
+ quota_source_label: str | None = None,
+ user: str | None = None,
):
admin_component = self.components.admin
@@ -2101,7 +2099,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
workflow_run.expanded_form.wait_for_visible()
def workflow_create_new(
- self, annotation: Optional[str] = None, clear_placeholder: bool = False, save_workflow: bool = True
+ self, annotation: str | None = None, clear_placeholder: bool = False, save_workflow: bool = True
):
self.workflow_index_open()
self.sleep_for(self.wait_types.UX_RENDER)
@@ -2172,7 +2170,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
self.scroll_into_view(tool_element)
tool_link.wait_for_and_click()
- def run_environment_test_tool(self, inttest_value="42", select_storage: Optional[str] = None):
+ def run_environment_test_tool(self, inttest_value="42", select_storage: str | None = None):
self.home()
self.tool_open("environment_variables")
if select_storage:
@@ -2648,7 +2646,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
)
visualize_tab_button.click()
- def show_dataset_visualization(self, hid: int, visualization_id: str, screenshot_name: Optional[str] = None):
+ def show_dataset_visualization(self, hid: int, visualization_id: str, screenshot_name: str | None = None):
self.show_dataset_visualizations(hid)
self.components.visualization.matched_plugin(id=visualization_id).wait_for_visible()
self.screenshot_if(screenshot_name)
@@ -2867,7 +2865,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
return self.wait_for_selector(selector, wait_type=WAIT_TYPES.JOB_COMPLETION)
def _clear_tooltip(self, tooltip_component):
- last_timeout: Optional[SeleniumTimeoutException] = None
+ last_timeout: SeleniumTimeoutException | None = None
for _ in range(2):
if not tooltip_component.is_absent:
move_away_chain = self.action_chains()
@@ -2919,15 +2917,13 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
"""
return super().assert_absent_or_hidden_after_transitions(selector)
- def assert_tooltip_text(self, element, expected: Union[str, HasText], sleep: int = 0, click_away: bool = True):
+ def assert_tooltip_text(self, element, expected: str | HasText, sleep: int = 0, click_away: bool = True):
if hasattr(expected, "text"):
expected = cast(HasText, expected).text
text = self.get_tooltip_text(element, sleep=sleep, click_away=click_away)
assert text == expected, f"Tooltip text [{text}] was not expected text [{expected}]."
- def assert_tooltip_text_contains(
- self, element, expected: Union[str, HasText], sleep: int = 0, click_away: bool = True
- ):
+ def assert_tooltip_text_contains(self, element, expected: str | HasText, sleep: int = 0, click_away: bool = True):
if hasattr(expected, "text"):
expected = cast(HasText, expected).text
text = self.get_tooltip_text(element, sleep=sleep, click_away=click_away)
@@ -3169,7 +3165,7 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
return object_store_id
def _fill_configuration_template(
- self, name: str, description: Optional[str], parameters: list[ConfigTemplateParameter]
+ self, name: str, description: str | None, parameters: list[ConfigTemplateParameter]
):
self.components.tool_form.parameter_input(parameter="_meta_name").wait_for_and_send_keys(
name,
@@ -3237,10 +3233,10 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
def mouse_drag(
self,
from_element: WebElementProtocol,
- to_element: Optional[WebElementProtocol] = None,
+ to_element: WebElementProtocol | None = None,
from_offset=(0, 0),
to_offset=(0, 0),
- via_offsets: Optional[list[tuple[int, int]]] = None,
+ via_offsets: list[tuple[int, int]] | None = None,
):
if self._driver_impl.backend_type == "playwright":
pw_driver = cast("HasPlaywrightDriver", self._driver_impl)
diff --git a/lib/galaxy/selenium/playwright_element.py b/lib/galaxy/selenium/playwright_element.py
index 2e98896a7cf..3f493d20da1 100644
--- a/lib/galaxy/selenium/playwright_element.py
+++ b/lib/galaxy/selenium/playwright_element.py
@@ -6,7 +6,6 @@ written for Selenium's WebElement.
"""
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -54,13 +53,12 @@ class PlaywrightShadowRoot:
self._shadow_root = shadow_root_handle
self._driver = driver
- def find_element(self, by: str = "id", value: Optional[str] = None) -> "WebElementProtocol":
+ def find_element(self, by: str = "id", value: str | None = None) -> "WebElementProtocol":
if value is None:
raise ValueError("value parameter is required")
selector = self._driver._selenium_locator_to_playwright_selector(by, value)
result_handle = self._shadow_root.evaluate_handle(f"root => root.querySelector('{selector}')")
- element_handle = result_handle.as_element()
- if element_handle:
+ if element_handle := result_handle.as_element():
return PlaywrightElement(element_handle, self._driver)
raise Exception(f"No element found in shadow root with {by}='{value}'")
@@ -142,7 +140,7 @@ class PlaywrightElement:
"""
self._element.fill("")
- def get_attribute(self, name: str) -> Optional[str]:
+ def get_attribute(self, name: str) -> str | None:
"""
Get the value of an element attribute.
@@ -205,17 +203,16 @@ class PlaywrightElement:
handle = self._element.evaluate_handle("el => el.shadowRoot")
return PlaywrightShadowRoot(handle, self._driver)
- def find_element(self, by: str = "id", value: Optional[str] = None) -> "WebElementProtocol":
+ def find_element(self, by: str = "id", value: str | None = None) -> "WebElementProtocol":
"""Find a child element within this element."""
if value is None:
raise ValueError("value parameter is required")
selector = self._driver._selenium_locator_to_playwright_selector(by, value)
- found_element = self._element.query_selector(selector)
- if found_element:
+ if found_element := self._element.query_selector(selector):
return PlaywrightElement(found_element, self._driver)
raise Exception(f"No element found with {by}='{value}'")
- def find_elements(self, by: str = "id", value: Optional[str] = None) -> list["WebElementProtocol"]:
+ def find_elements(self, by: str = "id", value: str | None = None) -> list["WebElementProtocol"]:
"""Find all child elements matching the locator within this element."""
if value is None:
raise ValueError("value parameter is required")
diff --git a/lib/galaxy/selenium/smart_components.py b/lib/galaxy/selenium/smart_components.py
index 8ad59e13c3c..dbcf9281602 100644
--- a/lib/galaxy/selenium/smart_components.py
+++ b/lib/galaxy/selenium/smart_components.py
@@ -1,5 +1,4 @@
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -160,7 +159,7 @@ class SmartTarget:
return self._has_driver.axe_eval(context=self._target.element_locator[1])
def assert_no_axe_violations_with_impact_of_at_least(
- self, impact: Impact, excludes: Optional[list[str]] = None
+ self, impact: Impact, excludes: list[str] | None = None
) -> None:
self.wait_for_visible()
self.axe_eval().assert_no_violations_with_impact_of_at_least(impact, excludes=excludes)
diff --git a/lib/galaxy/selenium/web_element_protocol.py b/lib/galaxy/selenium/web_element_protocol.py
index 7e5deac2d2d..998526e6b54 100644
--- a/lib/galaxy/selenium/web_element_protocol.py
+++ b/lib/galaxy/selenium/web_element_protocol.py
@@ -6,7 +6,6 @@ PlaywrightElement wrapper implement this protocol.
"""
from typing import (
- Optional,
Protocol,
runtime_checkable,
)
@@ -50,7 +49,7 @@ class WebElementProtocol(Protocol):
"""Clear the text of an input or textarea element."""
...
- def get_attribute(self, name: str) -> Optional[str]:
+ def get_attribute(self, name: str) -> str | None:
"""Get the value of an element attribute."""
...
@@ -70,11 +69,11 @@ class WebElementProtocol(Protocol):
"""Submit a form element."""
...
- def find_element(self, by: str = "id", value: Optional[str] = None) -> "WebElementProtocol":
+ def find_element(self, by: str = "id", value: str | None = None) -> "WebElementProtocol":
"""Find a child element within this element."""
...
- def find_elements(self, by: str = "id", value: Optional[str] = None) -> list["WebElementProtocol"]:
+ def find_elements(self, by: str = "id", value: str | None = None) -> list["WebElementProtocol"]:
"""Find all child elements matching the locator within this element."""
...
diff --git a/lib/galaxy/short_term_storage/__init__.py b/lib/galaxy/short_term_storage/__init__.py
index 8c3dfca041d..31ae0596977 100644
--- a/lib/galaxy/short_term_storage/__init__.py
+++ b/lib/galaxy/short_term_storage/__init__.py
@@ -17,8 +17,6 @@ from datetime import datetime
from pathlib import Path
from typing import (
Any,
- Optional,
- Union,
)
from uuid import (
UUID,
@@ -53,17 +51,17 @@ class ShortTermStorageConfiguration:
@dataclass
class ShortTermStorageTargetSecurity:
- user_id: Optional[int] = None
- session_id: Optional[int] = None
+ user_id: int | None = None
+ session_id: int | None = None
- def to_dict(self) -> dict[str, Optional[int]]:
+ def to_dict(self) -> dict[str, int | None]:
return {
"user_id": self.user_id,
"session_id": self.session_id,
}
@classmethod
- def from_dict(self, as_dict: dict[str, Optional[int]]) -> "ShortTermStorageTargetSecurity":
+ def from_dict(self, as_dict: dict[str, int | None]) -> "ShortTermStorageTargetSecurity":
return ShortTermStorageTargetSecurity(
user_id=as_dict.get("user_id"),
session_id=as_dict.get("session_id"),
@@ -93,7 +91,7 @@ class ShortTermStorageServeCompletedInformation:
class ShortTermStorageServeCancelledInformation:
target: ShortTermStorageTarget
status_code: int
- exception: Optional[dict[str, Any]]
+ exception: dict[str, Any] | None
@property
def message_exception(self) -> MessageException:
@@ -107,9 +105,7 @@ class ShortTermStorageServeCancelledInformation:
return exception_obj
-ShortTermStorageServeInformation = Union[
- ShortTermStorageServeCompletedInformation, ShortTermStorageServeCancelledInformation
-]
+ShortTermStorageServeInformation = ShortTermStorageServeCompletedInformation | ShortTermStorageServeCancelledInformation
class ShortTermStorageAllocator(metaclass=abc.ABCMeta):
@@ -119,8 +115,8 @@ class ShortTermStorageAllocator(metaclass=abc.ABCMeta):
self,
filename: str,
mime_type: str,
- duration: Optional[int] = None,
- security: Optional[ShortTermStorageTargetSecurity] = None,
+ duration: int | None = None,
+ security: ShortTermStorageTargetSecurity | None = None,
) -> ShortTermStorageTarget:
"""Return a new ShortTermStorageTarget for this short term file request."""
@@ -139,7 +135,7 @@ class ShortTermStorageMonitor(metaclass=abc.ABCMeta):
"""Indicate the file is ready to be served."""
@abc.abstractmethod
- def cancel(self, target: ShortTermStorageTarget, exception: Optional[MessageException] = None) -> None:
+ def cancel(self, target: ShortTermStorageTarget, exception: MessageException | None = None) -> None:
"""Store metadata for failed task.
Implementation is responsible for indicating target is finalized as well.
@@ -167,7 +163,7 @@ class ShortTermStorageManager(ShortTermStorageAllocator, ShortTermStorageMonitor
filename: str,
mime_type: str,
duration: OptionalNumberT = None,
- security: Optional[ShortTermStorageTargetSecurity] = None,
+ security: ShortTermStorageTargetSecurity | None = None,
) -> ShortTermStorageTarget:
if security is None:
security = ShortTermStorageTargetSecurity()
@@ -223,7 +219,7 @@ class ShortTermStorageManager(ShortTermStorageAllocator, ShortTermStorageMonitor
)
return serve_info
- def cancel(self, target: ShortTermStorageTarget, exception: Optional[MessageException] = None):
+ def cancel(self, target: ShortTermStorageTarget, exception: MessageException | None = None):
"""Write metadata for failed task."""
if exception:
exception_json = {
@@ -266,7 +262,7 @@ class ShortTermStorageManager(ShortTermStorageAllocator, ShortTermStorageMonitor
except ObjectNotFound:
return None
- def _directory(self, target: Union[UUID, ShortTermStorageTarget]) -> Path:
+ def _directory(self, target: UUID | ShortTermStorageTarget) -> Path:
if isinstance(target, ShortTermStorageTarget):
request_id = target.request_id
else:
diff --git a/lib/galaxy/structured_app/__init__.py b/lib/galaxy/structured_app/__init__.py
index e30f42bb252..a9f6d993a77 100644
--- a/lib/galaxy/structured_app/__init__.py
+++ b/lib/galaxy/structured_app/__init__.py
@@ -4,7 +4,6 @@ import abc
import threading
from typing import (
Any,
- Optional,
TYPE_CHECKING,
)
@@ -122,7 +121,7 @@ class MinimalApp(BasicSharedApp):
class MinimalManagerApp(MinimalApp):
# Minimal App that is sufficient to run Celery tasks
- amqp_internal_connection_obj: Optional[Connection]
+ amqp_internal_connection_obj: Connection | None
execution_timer_factory: "ExecutionTimerFactory"
carbon_intensity: float
file_sources: ConfiguredFileSources
@@ -172,7 +171,7 @@ class StructuredApp(MinimalManagerApp):
dependency_resolvers_view: DependencyResolversView
installed_repository_manager: "InstalledRepositoryManager"
container_finder: ContainerFinder
- tool_dependency_dir: Optional[str]
+ tool_dependency_dir: str | None
test_data_resolver: test_data.TestDataResolver
trs_proxy: TrsProxy
vault: Vault
@@ -180,7 +179,7 @@ class StructuredApp(MinimalManagerApp):
queue_worker: Any # 'galaxy.queue_worker.GalaxyQueueWorker'
data_provider_registry: Any # 'galaxy.visualization.data_providers.registry.DataProviderRegistry'
tool_cache: "ToolCache"
- tool_shed_repository_cache: Optional[ToolShedRepositoryCache]
+ tool_shed_repository_cache: ToolShedRepositoryCache | None
watchers: "ConfigWatchers"
workflow_scheduling_manager: Any # 'galaxy.workflow.scheduling_manager.WorkflowSchedulingManager'
api_keys_manager: Any # 'galaxy.managers.api_keys.ApiKeyManager'
diff --git a/lib/galaxy/tool_shed/galaxy_install/client.py b/lib/galaxy/tool_shed/galaxy_install/client.py
index f274a41113e..936547ca9f3 100644
--- a/lib/galaxy/tool_shed/galaxy_install/client.py
+++ b/lib/galaxy/tool_shed/galaxy_install/client.py
@@ -1,11 +1,9 @@
import threading
from typing import (
Any,
- Optional,
runtime_checkable,
TYPE_CHECKING,
TypeVar,
- Union,
)
from typing_extensions import Protocol
@@ -38,11 +36,11 @@ class DataManagersInterface(Protocol):
def load_manager_from_elem(
self, data_manager_elem, tool_path=None, add_manager=True
- ) -> Optional[DataManagerInterface]: ...
+ ) -> DataManagerInterface | None: ...
- def get_manager(self, data_manager_id: str) -> Optional[DataManagerInterface]: ...
+ def get_manager(self, data_manager_id: str) -> DataManagerInterface | None: ...
- def remove_manager(self, manager_ids: Union[str, list[str]]) -> None: ...
+ def remove_manager(self, manager_ids: str | list[str]) -> None: ...
ToolBoxType = TypeVar("ToolBoxType", bound="AbstractToolBox", contravariant=True)
diff --git a/lib/galaxy/tool_shed/galaxy_install/install_manager.py b/lib/galaxy/tool_shed/galaxy_install/install_manager.py
index 6cacd54e71b..d8a4f708659 100644
--- a/lib/galaxy/tool_shed/galaxy_install/install_manager.py
+++ b/lib/galaxy/tool_shed/galaxy_install/install_manager.py
@@ -3,7 +3,6 @@ import logging
import os
from typing import (
Any,
- Optional,
)
from sqlalchemy import or_
@@ -78,7 +77,7 @@ class InstallRepositoryManager:
app: InstallationTarget
tpm: tool_panel_manager.ToolPanelManager
- def __init__(self, app: InstallationTarget, tpm: Optional[tool_panel_manager.ToolPanelManager] = None):
+ def __init__(self, app: InstallationTarget, tpm: tool_panel_manager.ToolPanelManager | None = None):
self.app = app
self.install_model = self.app.install_model
self._view = views.DependencyResolversView(app)
diff --git a/lib/galaxy/tool_shed/galaxy_install/installed_repository_manager.py b/lib/galaxy/tool_shed/galaxy_install/installed_repository_manager.py
index 0e53c48051f..536f17a1f41 100644
--- a/lib/galaxy/tool_shed/galaxy_install/installed_repository_manager.py
+++ b/lib/galaxy/tool_shed/galaxy_install/installed_repository_manager.py
@@ -9,7 +9,6 @@ import shutil
from typing import (
Any,
no_type_check,
- Optional,
)
from galaxy import util
@@ -611,7 +610,7 @@ class InstalledRepositoryManager:
str(repository.installed_changeset_revision),
)
- def get_repository_install_dir(self, tool_shed_repository: ToolShedRepository) -> Optional[str]:
+ def get_repository_install_dir(self, tool_shed_repository: ToolShedRepository) -> str | None:
for tool_path in self.tool_paths:
ts = common_util.remove_port_from_tool_shed_url(str(tool_shed_repository.tool_shed))
relative_path = os.path.join(
diff --git a/lib/galaxy/tool_shed/galaxy_install/metadata/installed_repository_metadata_manager.py b/lib/galaxy/tool_shed/galaxy_install/metadata/installed_repository_metadata_manager.py
index 11a185a8808..3d354b68904 100644
--- a/lib/galaxy/tool_shed/galaxy_install/metadata/installed_repository_metadata_manager.py
+++ b/lib/galaxy/tool_shed/galaxy_install/metadata/installed_repository_metadata_manager.py
@@ -2,7 +2,6 @@ import logging
import os
from typing import (
Any,
- Optional,
)
from sqlalchemy import false
@@ -28,21 +27,20 @@ log = logging.getLogger(__name__)
class InstalledRepositoryMetadataManager(GalaxyMetadataGenerator):
-
def __init__(
self,
app: InstallationTarget,
- tpm: Optional[tool_panel_manager.ToolPanelManager] = None,
- repository: Optional[ToolShedRepository] = None,
- changeset_revision: Optional[str] = None,
- repository_clone_url: Optional[str] = None,
- shed_config_dict: Optional[dict[str, Any]] = None,
- relative_install_dir: Optional[str] = None,
- repository_files_dir: Optional[str] = None,
+ tpm: tool_panel_manager.ToolPanelManager | None = None,
+ repository: ToolShedRepository | None = None,
+ changeset_revision: str | None = None,
+ repository_clone_url: str | None = None,
+ shed_config_dict: dict[str, Any] | None = None,
+ relative_install_dir: str | None = None,
+ repository_files_dir: str | None = None,
resetting_all_metadata_on_repository: bool = False,
updating_installed_repository: bool = False,
persist: bool = False,
- metadata_dict: Optional[dict[str, Any]] = None,
+ metadata_dict: dict[str, Any] | None = None,
):
super().__init__(
app,
@@ -189,7 +187,7 @@ class InstalledRepositoryMetadataManager(GalaxyMetadataGenerator):
return message, status
def set_repository(
- self, repository, relative_install_dir: Optional[str] = None, changeset_revision: Optional[str] = None
+ self, repository, relative_install_dir: str | None = None, changeset_revision: str | None = None
):
super().set_repository(repository)
self.repository_clone_url = common_util.generate_clone_url_for_installed_repository(self.app, repository)
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 4c6e715f11d..705f0000271 100644
--- a/lib/galaxy/tool_shed/galaxy_install/tools/data_manager.py
+++ b/lib/galaxy/tool_shed/galaxy_install/tools/data_manager.py
@@ -4,7 +4,6 @@ import os
import time
from typing import (
Any,
- Optional,
)
from galaxy.tool_shed.galaxy_install.client import (
@@ -32,13 +31,13 @@ SHED_DATA_MANAGER_CONF_XML = """
class DataManagerHandler:
app: InstallationTarget
- root: Optional[Element] = None
+ root: Element | None = None
def __init__(self, app: InstallationTarget):
self.app = app
@property
- def data_managers_path(self) -> Optional[str]:
+ def data_managers_path(self) -> str | None:
tree, error_message = parse_xml(self.app.config.shed_data_manager_config_file)
if tree:
root = tree.getroot()
diff --git a/lib/galaxy/tool_shed/metadata/metadata_generator.py b/lib/galaxy/tool_shed/metadata/metadata_generator.py
index 1e26339029e..17c20425c5d 100644
--- a/lib/galaxy/tool_shed/metadata/metadata_generator.py
+++ b/lib/galaxy/tool_shed/metadata/metadata_generator.py
@@ -4,7 +4,6 @@ import tempfile
from typing import (
Any,
cast,
- Optional,
TYPE_CHECKING,
Union,
)
@@ -70,12 +69,12 @@ class RepositoryMetadataToolDict(TypedDict):
name: str
version: str
profile: str
- description: Optional[str]
- version_string_cmd: Optional[str]
+ description: str | None
+ version_string_cmd: str | None
tool_config: str
tool_type: str
- requirements: Optional[Any]
- tests: Optional[Any]
+ requirements: Any | None
+ tests: Any | None
add_to_tool_panel: bool
@@ -83,19 +82,19 @@ class RepositoryProtocol(Protocol):
name: str
id: str
- def repo_path(self, app) -> Optional[str]: ...
+ def repo_path(self, app) -> str | None: ...
class BaseMetadataGenerator:
app: Union["BasicSharedApp", InstallationTarget]
- repository: Optional[RepositoryProtocol]
+ repository: RepositoryProtocol | None
invalid_file_tups: list[InvalidFileT]
- changeset_revision: Optional[str]
- repository_clone_url: Optional[str]
+ changeset_revision: str | None
+ repository_clone_url: str | None
shed_config_dict: dict[str, Any]
metadata_dict: dict[str, Any]
- relative_install_dir: Optional[str]
- repository_files_dir: Optional[str]
+ relative_install_dir: str | None
+ repository_files_dir: str | None
persist: bool
def initial_metadata_dict(self) -> dict[str, Any]:
@@ -823,13 +822,13 @@ class BaseMetadataGenerator:
return False
return True
- def set_changeset_revision(self, changeset_revision: Optional[str]):
+ def set_changeset_revision(self, changeset_revision: str | None):
self.changeset_revision = changeset_revision
- def set_relative_install_dir(self, relative_install_dir: Optional[str]):
+ def set_relative_install_dir(self, relative_install_dir: str | None):
self.relative_install_dir = relative_install_dir
- def _reset_attributes_after_repository_update(self, relative_install_dir: Optional[str]):
+ def _reset_attributes_after_repository_update(self, relative_install_dir: str | None):
self.metadata_dict = self.initial_metadata_dict()
self.set_relative_install_dir(relative_install_dir)
self.set_repository_files_dir()
@@ -838,7 +837,7 @@ class BaseMetadataGenerator:
self.persist = False
self.invalid_file_tups = []
- def set_repository_files_dir(self, repository_files_dir: Optional[str] = None):
+ def set_repository_files_dir(self, repository_files_dir: str | None = None):
self.repository_files_dir = repository_files_dir
def _update_repository_dependencies_metadata(
@@ -846,7 +845,7 @@ class BaseMetadataGenerator:
metadata: dict[str, Any],
repository_dependency_tups: list[tuple],
is_valid: bool,
- description: Optional[str],
+ description: str | None,
) -> dict[str, Any]:
if is_valid:
repository_dependencies_dict = metadata.get("repository_dependencies", None)
@@ -875,15 +874,15 @@ class GalaxyMetadataGenerator(BaseMetadataGenerator):
"""A MetadataGenerator building on Galaxy's app and repository constructs."""
app: InstallationTarget
- repository: Optional[ToolShedRepository] # type: ignore[assignment]
+ repository: ToolShedRepository | None # type: ignore[assignment]
def __init__(
self,
app: InstallationTarget,
repository=None,
- changeset_revision: Optional[str] = None,
- repository_clone_url: Optional[str] = None,
- shed_config_dict: Optional[dict[str, Any]] = None,
+ changeset_revision: str | None = None,
+ repository_clone_url: str | None = None,
+ shed_config_dict: dict[str, Any] | None = None,
relative_install_dir=None,
repository_files_dir=None,
resetting_all_metadata_on_repository=False,
@@ -933,7 +932,7 @@ class GalaxyMetadataGenerator(BaseMetadataGenerator):
return metadata_dict
def set_repository(
- self, repository, relative_install_dir: Optional[str] = None, changeset_revision: Optional[str] = None
+ self, repository, relative_install_dir: str | None = None, changeset_revision: str | None = None
):
self.repository = repository
if relative_install_dir is None and self.repository is not None:
diff --git a/lib/galaxy/tool_shed/unittest_utils/__init__.py b/lib/galaxy/tool_shed/unittest_utils/__init__.py
index 24c274e252a..311bdcfde31 100644
--- a/lib/galaxy/tool_shed/unittest_utils/__init__.py
+++ b/lib/galaxy/tool_shed/unittest_utils/__init__.py
@@ -4,9 +4,7 @@ from typing import (
Any,
cast,
NamedTuple,
- Optional,
TYPE_CHECKING,
- Union,
)
from galaxy.model.migrations import (
@@ -72,7 +70,7 @@ class Config:
integrated_tool_panel_config: str
shed_tool_config_file: str
shed_tool_data_path: str
- migrated_tools_config: Optional[str] = None
+ migrated_tools_config: str | None = None
shed_tools_dir: str
edam_panel_views: list = []
tool_configs: list = []
@@ -111,7 +109,7 @@ class TestToolBox(AbstractToolBox):
return tool
def _get_tool_shed_repository(
- self, tool_shed: str, name: str, owner: str, installed_changeset_revision: Optional[str]
+ self, tool_shed: str, name: str, owner: str, installed_changeset_revision: str | None
) -> "ToolShedRepository":
return get_installed_repository(
self.app,
@@ -155,13 +153,13 @@ class StandaloneDataManagers(DataManagersInterface):
def load_manager_from_elem(
self, data_manager_elem, tool_path=None, add_manager=True
- ) -> Optional[DataManagerInterface]:
+ ) -> DataManagerInterface | None:
return DummyDataManager()
- def get_manager(self, data_manager_id: str) -> Optional[DataManagerInterface]:
+ def get_manager(self, data_manager_id: str) -> DataManagerInterface | None:
return None
- def remove_manager(self, manager_ids: Union[str, list[str]]) -> None:
+ def remove_manager(self, manager_ids: str | list[str]) -> None:
return None
@property
@@ -176,13 +174,13 @@ class StandaloneInstallationTarget(InstallationTarget):
security: IdEncodingHelper
_toolbox: TestToolBox
_toolbox_lock: threading.RLock = threading.RLock()
- tool_shed_repository_cache: Optional[ToolShedRepositoryCache] = None
+ tool_shed_repository_cache: ToolShedRepositoryCache | None = None
data_managers = StandaloneDataManagers()
def __init__(
self,
target_directory: Path,
- tool_shed_target: Optional[ToolShedTarget] = None,
+ tool_shed_target: ToolShedTarget | None = None,
):
tool_root_dir = target_directory / "tools"
config: Config = Config()
@@ -210,7 +208,7 @@ class StandaloneInstallationTarget(InstallationTarget):
False,
).run()
self.install_model = install_mapping.configure_model_mapping(install_engine)
- registry_config: Optional[Path] = None
+ registry_config: Path | None = None
if tool_shed_target:
registry_config = target_directory / "tool_sheds_conf.xml"
with registry_config.open("w") as f:
@@ -236,7 +234,7 @@ class StandaloneInstallationTarget(InstallationTarget):
return self._tool_data_tables
@property
- def tool_dependency_dir(self) -> Optional[str]:
+ def tool_dependency_dir(self) -> str | None:
return None
def reload_toolbox(self):
diff --git a/lib/galaxy/tool_shed/util/container_util.py b/lib/galaxy/tool_shed/util/container_util.py
index ea3e4c984b5..c682a9febbf 100644
--- a/lib/galaxy/tool_shed/util/container_util.py
+++ b/lib/galaxy/tool_shed/util/container_util.py
@@ -1,5 +1,4 @@
import logging
-from typing import Union
from galaxy.util.tool_shed.common_util import remove_protocol_from_tool_shed_url
@@ -14,8 +13,8 @@ def generate_repository_dependencies_key_for_repository(
repository_name: str,
repository_owner: str,
changeset_revision: str,
- prior_installation_required: Union[bool, str],
- only_if_compiling_contained_td: Union[bool, str],
+ prior_installation_required: bool | str,
+ only_if_compiling_contained_td: bool | str,
) -> str:
"""
Assumes tool shed is current tool shed since repository dependencies across tool sheds
diff --git a/lib/galaxy/tool_shed/util/hg_util.py b/lib/galaxy/tool_shed/util/hg_util.py
index 9256b56b60f..fc8f87f60a3 100644
--- a/lib/galaxy/tool_shed/util/hg_util.py
+++ b/lib/galaxy/tool_shed/util/hg_util.py
@@ -1,9 +1,6 @@
import logging
import os
import subprocess
-from typing import (
- Optional,
-)
from galaxy.tool_shed.util import basic_util
from galaxy.util import unicodify
@@ -13,7 +10,7 @@ log = logging.getLogger(__name__)
INITIAL_CHANGELOG_HASH = "000000000000"
-def clone_repository(repository_clone_url: str, repository_file_dir: str, ctx_rev=None) -> tuple[bool, Optional[str]]:
+def clone_repository(repository_clone_url: str, repository_file_dir: str, ctx_rev=None) -> tuple[bool, str | None]:
"""
Clone the repository up to the specified changeset_revision. No subsequent revisions will be
present in the cloned repository.
@@ -62,7 +59,7 @@ def get_changectx_for_changeset(repo, changeset_revision, **kwd):
return None
-def get_config_from_disk(config_file: str, relative_install_dir: str) -> Optional[str]:
+def get_config_from_disk(config_file: str, relative_install_dir: str) -> str | None:
for root, _dirs, files in os.walk(relative_install_dir):
if root.find(".hg") < 0:
for name in files:
diff --git a/lib/galaxy/tool_shed/util/repository_util.py b/lib/galaxy/tool_shed/util/repository_util.py
index 6da054d11cb..03477308c5c 100644
--- a/lib/galaxy/tool_shed/util/repository_util.py
+++ b/lib/galaxy/tool_shed/util/repository_util.py
@@ -4,9 +4,7 @@ import re
import shutil
from typing import (
Any,
- Optional,
TYPE_CHECKING,
- Union,
)
from urllib.error import HTTPError
@@ -40,7 +38,7 @@ VALID_REPOSITORYNAME_RE = re.compile(r"^[a-z0-9\_]+$")
def check_for_updates(
tool_shed_registry: Registry,
install_model_context: install_model_scoped_session,
- repository_id: Optional[int] = None,
+ repository_id: int | None = None,
) -> tuple[str, str]:
message = ""
status = "ok"
@@ -244,12 +242,12 @@ def get_absolute_path_to_file_in_repository(repo_files_dir, file_name):
def get_installed_repository(
app: "InstallationTarget",
- tool_shed: Optional[str] = None,
- name: Optional[str] = None,
- owner: Optional[str] = None,
- changeset_revision: Optional[str] = None,
- installed_changeset_revision: Optional[str] = None,
- repository_id: Optional[int] = None,
+ tool_shed: str | None = None,
+ name: str | None = None,
+ owner: str | None = None,
+ changeset_revision: str | None = None,
+ installed_changeset_revision: str | None = None,
+ repository_id: int | None = None,
from_cache: bool = False,
) -> ToolShedRepository:
"""
@@ -332,10 +330,10 @@ def get_prior_import_or_install_required_dict(app: "InstallationTarget", tsr_ids
return prior_import_or_install_required_dict
-ToolDependenciesDictT = dict[str, Union[dict[str, Any], list[dict[str, Any]]]]
+ToolDependenciesDictT = dict[str, dict[str, Any] | list[dict[str, Any]]]
OldRepositoryTupleT = tuple[str, str, str, str, str, ToolDependenciesDictT]
-RepositoryTupleT = tuple[str, str, str, str, str, Optional[Any], ToolDependenciesDictT]
-AnyRepositoryTupleT = Union[OldRepositoryTupleT, RepositoryTupleT]
+RepositoryTupleT = tuple[str, str, str, str, str, Any | None, ToolDependenciesDictT]
+AnyRepositoryTupleT = OldRepositoryTupleT | RepositoryTupleT
def get_repo_info_tuple_contents(repo_info_tuple: AnyRepositoryTupleT) -> RepositoryTupleT:
diff --git a/lib/galaxy/tool_shed/util/tool_util.py b/lib/galaxy/tool_shed/util/tool_util.py
index 6f08ff89e14..7a265ca446c 100644
--- a/lib/galaxy/tool_shed/util/tool_util.py
+++ b/lib/galaxy/tool_shed/util/tool_util.py
@@ -1,6 +1,5 @@
import os
import shutil
-from typing import Optional
from galaxy import util
from galaxy.datatypes.sniff import is_column_based
@@ -35,7 +34,7 @@ def build_tool_panel_section_select_field(app):
return select_field
-def copy_sample_file(tool_data_path: str, filename: str, dest_path: Optional[str] = None) -> str:
+def copy_sample_file(tool_data_path: str, filename: str, dest_path: str | None = None) -> str:
"""
Copies a sample file at `filename` to `the dest_path`
directory and strips the '.sample' extensions from `filename`.
@@ -63,9 +62,9 @@ def copy_sample_file(tool_data_path: str, filename: str, dest_path: Optional[str
def copy_sample_files(
tool_data_path: str,
sample_files,
- tool_path: Optional[str] = None,
+ tool_path: str | None = None,
sample_files_copied=None,
- dest_path: Optional[str] = None,
+ dest_path: str | None = None,
) -> None:
"""
Copy all appropriate files to dest_path in the local Galaxy environment that have not
@@ -90,7 +89,7 @@ def generate_message_for_invalid_tools(
app,
invalid_file_tups: list,
repository,
- metadata_dict: Optional[dict],
+ metadata_dict: dict | None,
as_html: bool = True,
displaying_invalid_tool: bool = False,
) -> str:
diff --git a/lib/galaxy/tool_util/biotools/interface.py b/lib/galaxy/tool_util/biotools/interface.py
index ab7ab604840..b13ea5a5d2f 100644
--- a/lib/galaxy/tool_util/biotools/interface.py
+++ b/lib/galaxy/tool_util/biotools/interface.py
@@ -1,9 +1,6 @@
import re
from typing import (
Any,
- Dict,
- List,
- Optional,
)
TERM_PATTERN = re.compile(r"https?://edamontology.org/(.*)")
@@ -13,19 +10,19 @@ class ParsedBiotoolsEntry:
"""Provide XML wrapper relevant entities from a bio.tool entry - topics and operations."""
biotoolsID: str
- edam_topics: List[str]
- edam_operations: List[str]
+ edam_topics: list[str]
+ edam_operations: list[str]
class BiotoolsEntry:
"""Parse the RAW entries of interest for Galaxy from a bio.tools entry."""
biotoolsID: str
- topic: List[dict]
- function: List[dict]
+ topic: list[dict]
+ function: list[dict]
@staticmethod
- def from_json(from_json: Dict[str, Any]) -> "BiotoolsEntry":
+ def from_json(from_json: dict[str, Any]) -> "BiotoolsEntry":
entry = BiotoolsEntry()
entry.biotoolsID = from_json["biotoolsID"]
entry.topic = from_json.get("topic", [])
@@ -45,7 +42,7 @@ class BiotoolsEntry:
return parsed
-def simplify_edam_dicts(a_list: List[Dict[str, str]]):
+def simplify_edam_dicts(a_list: list[dict[str, str]]):
terms = []
for term in map(simplify_edam_dict, a_list):
if term:
@@ -53,10 +50,9 @@ def simplify_edam_dicts(a_list: List[Dict[str, str]]):
return terms
-def simplify_edam_dict(as_dict: Dict[str, str]) -> Optional[str]:
+def simplify_edam_dict(as_dict: dict[str, str]) -> str | None:
uri = as_dict["uri"]
- match = TERM_PATTERN.match(uri)
- if match:
+ if match := TERM_PATTERN.match(uri):
return match.group(1)
else:
# TODO: log problem...
diff --git a/lib/galaxy/tool_util/biotools/source.py b/lib/galaxy/tool_util/biotools/source.py
index f5fcc54041c..b961c916aca 100644
--- a/lib/galaxy/tool_util/biotools/source.py
+++ b/lib/galaxy/tool_util/biotools/source.py
@@ -1,12 +1,7 @@
import functools
import json
import os
-from typing import (
- Callable,
- Dict,
- List,
- Optional,
-)
+from collections.abc import Callable
from galaxy.util import (
DEFAULT_SOCKET_TIMEOUT,
@@ -16,7 +11,7 @@ from .interface import BiotoolsEntry
class BiotoolsMetadataSource:
- def get_biotools_metadata(self, biotools_reference: str) -> Optional[BiotoolsEntry]:
+ def get_biotools_metadata(self, biotools_reference: str) -> BiotoolsEntry | None:
"""Return a BiotoolsEntry if available."""
@@ -26,7 +21,7 @@ class GitContentBiotoolsMetadataSource(BiotoolsMetadataSource):
def __init__(self, content_directory):
self._content_directory = content_directory
- def get_biotools_metadata(self, biotools_reference: str) -> Optional[BiotoolsEntry]:
+ def get_biotools_metadata(self, biotools_reference: str) -> BiotoolsEntry | None:
"""Return a BiotoolsEntry if available."""
path = os.path.join(self._content_directory, "data", biotools_reference, f"{biotools_reference}.biotools.json")
if not os.path.exists(path):
@@ -37,9 +32,9 @@ class GitContentBiotoolsMetadataSource(BiotoolsMetadataSource):
class InMemoryCache:
- backend: Dict[str, Optional[str]] = {}
+ backend: dict[str, str | None] = {}
- def get(self, key: str, createfunc: Callable[[], Optional[str]]):
+ def get(self, key: str, createfunc: Callable[[], str | None]):
backend = self.backend
if key not in backend:
backend[key] = createfunc()
@@ -53,7 +48,7 @@ class ApiBiotoolsMetadataSource(BiotoolsMetadataSource):
def __init__(self, cache=None):
self._cache = cache or InMemoryCache()
- def _raw_get_metadata(self, biotools_reference) -> Optional[str]:
+ def _raw_get_metadata(self, biotools_reference) -> str | None:
api_url = f"https://bio.tools/api/tool/{biotools_reference}?format=json"
try:
req = requests.get(api_url, timeout=DEFAULT_SOCKET_TIMEOUT)
@@ -63,7 +58,7 @@ class ApiBiotoolsMetadataSource(BiotoolsMetadataSource):
except Exception:
return None
- def get_biotools_metadata(self, biotools_reference: str) -> Optional[BiotoolsEntry]:
+ def get_biotools_metadata(self, biotools_reference: str) -> BiotoolsEntry | None:
createfunc = functools.partial(self._raw_get_metadata, biotools_reference)
content = self._cache.get(key=biotools_reference, createfunc=createfunc)
if content is not None:
@@ -73,8 +68,8 @@ class ApiBiotoolsMetadataSource(BiotoolsMetadataSource):
class CascadingBiotoolsMetadataSource(BiotoolsMetadataSource):
- def __init__(self, use_api=False, cache=None, content_directory: Optional[str] = None):
- sources: List[BiotoolsMetadataSource] = []
+ def __init__(self, use_api=False, cache=None, content_directory: str | None = None):
+ sources: list[BiotoolsMetadataSource] = []
if content_directory:
git_content_source = GitContentBiotoolsMetadataSource(content_directory)
sources.append(git_content_source)
@@ -83,7 +78,7 @@ class CascadingBiotoolsMetadataSource(BiotoolsMetadataSource):
sources.append(api_metadata_source)
self._sources = sources
- def get_biotools_metadata(self, biotools_reference: str) -> Optional[BiotoolsEntry]:
+ def get_biotools_metadata(self, biotools_reference: str) -> BiotoolsEntry | None:
for source in self._sources:
entry = source.get_biotools_metadata(biotools_reference)
if entry is not None:
@@ -93,7 +88,7 @@ class CascadingBiotoolsMetadataSource(BiotoolsMetadataSource):
class BiotoolsMetadataSourceConfig:
use_api: bool = False
- content_directory: Optional[str] = None
+ content_directory: str | None = None
cache = None
diff --git a/lib/galaxy/tool_util/client/landing.py b/lib/galaxy/tool_util/client/landing.py
index 87ea3b5044f..481bf6e595c 100644
--- a/lib/galaxy/tool_util/client/landing.py
+++ b/lib/galaxy/tool_util/client/landing.py
@@ -7,7 +7,6 @@ import random
import string
import sys
from dataclasses import dataclass
-from typing import Optional
import requests
import yaml
@@ -36,7 +35,7 @@ class Request:
template_id: str
catalog: str
public: bool
- client_secret: Optional[str]
+ client_secret: str | None
galaxy_url: str
diff --git a/lib/galaxy/tool_util/client/staging.py b/lib/galaxy/tool_util/client/staging.py
index a7c64e60f2c..f25b6470498 100644
--- a/lib/galaxy/tool_util/client/staging.py
+++ b/lib/galaxy/tool_util/client/staging.py
@@ -8,20 +8,15 @@ import abc
import json
import logging
import os
+from collections.abc import Callable
from typing import (
Any,
BinaryIO,
- Callable,
- Dict,
- List,
- Optional,
- Tuple,
+ Literal,
TYPE_CHECKING,
- Union,
)
import yaml
-from typing_extensions import Literal
from galaxy.tool_util.cwl.util import (
DirectoryUploadTarget,
@@ -55,41 +50,41 @@ class StagingInterface(metaclass=abc.ABCMeta):
"""
@abc.abstractmethod
- def _post(self, api_path: str, payload: Dict[str, Any]) -> Dict[str, Any]:
+ def _post(self, api_path: str, payload: dict[str, Any]) -> dict[str, Any]:
"""Make a post to the Galaxy API along supplied path."""
def _attach_file(self, path: str) -> BinaryIO:
return open(path, "rb")
- def _tools_post(self, payload: Dict[str, Any]) -> Dict[str, Any]:
+ def _tools_post(self, payload: dict[str, Any]) -> dict[str, Any]:
tool_response = self._post("tools", payload)
for job in tool_response.get("jobs", []):
self._handle_job(job)
return tool_response
- def _fetch_post(self, payload: Dict[str, Any]) -> Dict[str, Any]:
+ def _fetch_post(self, payload: dict[str, Any]) -> dict[str, Any]:
tool_response = self._post("tools/fetch", payload)
for job in tool_response.get("jobs", []):
self._handle_job(job)
return tool_response
@abc.abstractmethod
- def _handle_job(self, job_response: Dict[str, Any]):
+ def _handle_job(self, job_response: dict[str, Any]):
"""Implementer can decide if to wait for job(s) individually or not here."""
def stage(
self,
tool_or_workflow: Literal["tool", "workflow"],
history_id: str,
- job: Optional[Dict[str, Any]] = None,
- job_path: Optional[str] = None,
+ job: dict[str, Any] | None = None,
+ job_path: str | None = None,
use_path_paste: bool = LOAD_TOOLS_FROM_PATH,
to_posix_lines: bool = True,
job_dir: str = ".",
- resolve_data: Optional[Callable[[str], Optional[str]]] = None,
- ) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
- def upload_func_fetch(upload_target: UploadTarget) -> Dict[str, Any]:
- def _attach_file(upload_payload: Dict[str, Any], uri: str, index: int = 0) -> Dict[str, Union[str, bool]]:
+ resolve_data: Callable[[str], str | None] | None = None,
+ ) -> tuple[dict[str, Any], list[dict[str, Any]]]:
+ def upload_func_fetch(upload_target: UploadTarget) -> dict[str, Any]:
+ def _attach_file(upload_payload: dict[str, Any], uri: str, index: int = 0) -> dict[str, str | bool]:
uri = path_or_uri_to_uri(uri)
is_path = uri.startswith("file://")
if not is_path or use_path_paste:
@@ -181,8 +176,8 @@ class StagingInterface(metaclass=abc.ABCMeta):
return self._fetch_post(fetch_payload)
# Save legacy upload_func to target older Galaxy servers
- def upload_func(upload_target: UploadTarget) -> Dict[str, Any]:
- def _attach_file(upload_payload: Dict[str, Any], uri: str, index: int = 0) -> None:
+ def upload_func(upload_target: UploadTarget) -> dict[str, Any]:
+ def _attach_file(upload_payload: dict[str, Any], uri: str, index: int = 0) -> None:
uri = path_or_uri_to_uri(uri)
is_path = uri.startswith("file://")
if not is_path or use_path_paste:
@@ -252,11 +247,11 @@ class StagingInterface(metaclass=abc.ABCMeta):
raise ValueError(f"Unsupported type for upload_target: {type(upload_target)}")
def create_collection_func(
- element_identifiers: List[Dict[str, Any]],
+ element_identifiers: list[dict[str, Any]],
collection_type: str,
- rows: Optional[Dict[str, Any]] = None,
- name: Optional[str] = None,
- ) -> Dict[str, Any]:
+ rows: dict[str, Any] | None = None,
+ name: str | None = None,
+ ) -> dict[str, Any]:
payload = {
"name": name or "dataset collection",
"instance_type": "history",
@@ -305,12 +300,12 @@ class InteractorStaging(StagingInterface):
self.galaxy_interactor = galaxy_interactor
self._use_fetch_api = use_fetch_api
- def _post(self, api_path: str, payload: Dict[str, Any]) -> Dict[str, Any]:
+ def _post(self, api_path: str, payload: dict[str, Any]) -> dict[str, Any]:
response = self.galaxy_interactor._post(api_path, payload, json=True)
assert response.status_code == 200, response.text
return response.json()
- def _handle_job(self, job_response: Dict[str, Any]):
+ def _handle_job(self, job_response: dict[str, Any]):
self.galaxy_interactor.wait_for_job(job_response["id"])
@property
@@ -318,7 +313,7 @@ class InteractorStaging(StagingInterface):
return self._use_fetch_api
-def _file_path_to_name(file_path: Optional[str]) -> str:
+def _file_path_to_name(file_path: str | None) -> str:
if file_path is not None:
name = os.path.basename(file_path)
else:
@@ -328,12 +323,12 @@ def _file_path_to_name(file_path: Optional[str]) -> str:
def _upload_payload(
history_id: str, file_type: str = DEFAULT_FILE_TYPE, dbkey: str = DEFAULT_DBKEY, **kwd
-) -> Dict[str, Any]:
+) -> dict[str, Any]:
"""Adapted from BioBlend tools client."""
- payload: Dict[str, Any] = {}
+ payload: dict[str, Any] = {}
payload["history_id"] = history_id
payload["tool_id"] = UPLOAD_TOOL_ID
- tool_input: Dict[str, Any] = {}
+ tool_input: dict[str, Any] = {}
tool_input["file_type"] = file_type
tool_input["dbkey"] = dbkey
if not kwd.get("to_posix_lines", True):
diff --git a/lib/galaxy/tool_util/cwl/parser.py b/lib/galaxy/tool_util/cwl/parser.py
index 237af0dee55..1af665cfa99 100644
--- a/lib/galaxy/tool_util/cwl/parser.py
+++ b/lib/galaxy/tool_util/cwl/parser.py
@@ -15,12 +15,10 @@ from abc import (
from typing import (
Any,
cast,
- Dict,
- List,
+ Literal,
Optional,
overload,
TYPE_CHECKING,
- Union,
)
from uuid import (
UUID,
@@ -28,7 +26,6 @@ from uuid import (
)
from typing_extensions import (
- Literal,
TypedDict,
)
@@ -101,7 +98,7 @@ SUPPORTED_TOOL_REQUIREMENTS = [
SUPPORTED_WORKFLOW_REQUIREMENTS = SUPPORTED_TOOL_REQUIREMENTS + []
-ToolStateType = Dict[str, Union[None, str, bool, Dict[str, str]]]
+ToolStateType = dict[str, None | str | bool | dict[str, str]]
class InputInstanceDict(TypedDict, total=False):
@@ -120,7 +117,7 @@ class InputInstanceArrayDict(TypedDict):
type: str
name: str
title: str
- blocks: List[InputInstanceDict]
+ blocks: list[InputInstanceDict]
class ToolProxy(metaclass=ABCMeta):
@@ -129,9 +126,9 @@ class ToolProxy(metaclass=ABCMeta):
def __init__(
self,
tool: "Process",
- uuid: Union[UUID, str],
+ uuid: UUID | str,
raw_process_reference: Optional["RawProcessReference"] = None,
- tool_path: Optional[str] = None,
+ tool_path: str | None = None,
):
self._tool = tool
self.uuid = uuid
@@ -144,7 +141,7 @@ class ToolProxy(metaclass=ABCMeta):
if "format" in input_field:
del input_field["format"]
- def job_proxy(self, input_dict: Dict[str, Any], output_dict, job_directory: str = "."):
+ def job_proxy(self, input_dict: dict[str, Any], output_dict, job_directory: str = "."):
"""Build a cwltool.job.Job describing computation using a input_json
Galaxy will generate mapping the Galaxy description of the inputs into
a cwltool compatible variant.
@@ -157,10 +154,9 @@ class ToolProxy(metaclass=ABCMeta):
return raw_id
def galaxy_id(self) -> str:
- raw_id = self.id
tool_id = None
# don't reduce "search.cwl#index" to search
- if raw_id:
+ if raw_id := self.id:
tool_id = os.path.basename(raw_id)
# tool_id = os.path.splitext(os.path.basename(raw_id))[0]
if not tool_id:
@@ -178,7 +174,7 @@ class ToolProxy(metaclass=ABCMeta):
"""Return InputInstance objects describing mapping to Galaxy inputs."""
@abstractmethod
- def output_instances(self) -> List["OutputInstance"]:
+ def output_instances(self) -> list["OutputInstance"]:
"""Return OutputInstance objects describing mapping to Galaxy inputs."""
@abstractmethod
@@ -210,7 +206,7 @@ class ToolProxy(metaclass=ABCMeta):
@staticmethod
def from_persistent_representation(
- as_object: Dict[str, Any], strict_cwl_validation: bool = True, tool_directory: Optional[str] = None
+ as_object: dict[str, Any], strict_cwl_validation: bool = True, tool_directory: str | None = None
) -> "ToolProxy":
"""Recover an object serialized with to_persistent_representation."""
if "class" not in as_object:
@@ -224,14 +220,14 @@ class ToolProxy(metaclass=ABCMeta):
return loaded_object
@property
- def requirements(self) -> List:
+ def requirements(self) -> list:
return getattr(self._tool, "requirements", [])
- def hints_or_requirements_of_class(self, class_name: str) -> List:
+ def hints_or_requirements_of_class(self, class_name: str) -> list:
reqs_and_hints = self.requirements + getattr(self._tool, "hints", [])
return [hint for hint in reqs_and_hints if hint["class"] == class_name]
- def software_requirements(self) -> List:
+ def software_requirements(self) -> list:
# Roughest imaginable pass at parsing requirements, really need to take in specs, handle
# multiple versions, etc...
requirements = []
@@ -243,10 +239,10 @@ class ToolProxy(metaclass=ABCMeta):
requirements.append((package["package"], first_version))
return requirements
- def resource_requirements(self) -> List:
+ def resource_requirements(self) -> list:
return self.hints_or_requirements_of_class("ResourceRequirement")
- def credentials_requirements(self) -> List:
+ def credentials_requirements(self) -> list:
return self.hints_or_requirements_of_class("CredentialsRequirement")
@@ -263,9 +259,8 @@ class CommandLineToolProxy(ToolProxy):
return doc
def label(self):
- label = self._tool.tool.get("label")
- if label is not None:
+ if (label := self._tool.tool.get("label")) is not None:
return label.partition(":")[0] # return substring before ':'
else:
return ""
@@ -324,16 +319,16 @@ class ExpressionToolProxy(CommandLineToolProxy):
class JobProxy:
_is_command_line_job: bool
- def __init__(self, tool_proxy: ToolProxy, input_dict: Dict[str, Any], output_dict, job_directory: str):
+ def __init__(self, tool_proxy: ToolProxy, input_dict: dict[str, Any], output_dict, job_directory: str):
assert RuntimeContext is not None, "cwltool is not installed, cannot run CWL jobs"
self._tool_proxy = tool_proxy
self._input_dict = input_dict
self._output_dict = output_dict
self._job_directory = job_directory
- self._final_output: Optional[CWLObjectType] = None
+ self._final_output: CWLObjectType | None = None
self._ok = True
- self._cwl_job: Optional[JobsType] = None
+ self._cwl_job: JobsType | None = None
self._normalize_job()
@@ -557,10 +552,10 @@ class JobProxy:
class WorkflowProxy:
- def __init__(self, workflow: "workflow.Workflow", workflow_path: Optional[str] = None):
+ def __init__(self, workflow: "workflow.Workflow", workflow_path: str | None = None):
self._workflow = workflow
self._workflow_path = workflow_path
- self._step_proxies: Optional[List[Union[SubworkflowStepProxy, ToolStepProxy]]] = None
+ self._step_proxies: list[SubworkflowStepProxy | ToolStepProxy] | None = None
@property
def cwl_id(self):
@@ -591,7 +586,7 @@ class WorkflowProxy:
def tool_reference_proxies(self):
"""Fetch tool source definitions for all referenced tools."""
- references: List[ToolProxy] = []
+ references: list[ToolProxy] = []
for step in self.step_proxies():
references.extend(step.tool_reference_proxies())
return references
@@ -634,7 +629,7 @@ class WorkflowProxy:
cwl_ids_to_index = self.cwl_ids_to_index(step_proxies)
input_connections_by_step = []
for step_proxy in step_proxies:
- input_connections_step: Dict[str, List[Dict[str, str]]] = {}
+ input_connections_step: dict[str, list[dict[str, str]]] = {}
for input_proxy in step_proxy.input_proxies:
cwl_source_id = input_proxy.cwl_source_id
input_name = input_proxy.input_name
@@ -747,11 +742,11 @@ class WorkflowProxy:
def tool_proxy(
- tool_path: Optional[str] = None,
+ tool_path: str | None = None,
tool_object=None,
strict_cwl_validation: bool = True,
- tool_directory: Optional[str] = None,
- uuid: Optional[Union[UUID, str]] = None,
+ tool_directory: str | None = None,
+ uuid: UUID | str | None = None,
) -> ToolProxy:
"""Provide a proxy object to cwltool data structures to just
grab relevant data.
@@ -767,7 +762,7 @@ def tool_proxy(
def tool_proxy_from_persistent_representation(
- persisted_tool: Dict[str, Any], strict_cwl_validation: bool = True, tool_directory: Optional[str] = None
+ persisted_tool: dict[str, Any], strict_cwl_validation: bool = True, tool_directory: str | None = None
) -> ToolProxy:
"""Load a ToolProxy from a previously persisted representation."""
ensure_cwltool_available()
@@ -795,11 +790,11 @@ def load_job_proxy(job_directory: str, strict_cwl_validation: bool = True) -> Jo
def _to_cwl_tool_object(
- tool_path: Optional[str] = None,
+ tool_path: str | None = None,
tool_object=None,
strict_cwl_validation: bool = False,
- tool_directory: Optional[str] = None,
- uuid: Optional[Union[UUID, str]] = None,
+ tool_directory: str | None = None,
+ uuid: UUID | str | None = None,
) -> ToolProxy:
if uuid is None:
uuid = str(uuid4())
@@ -840,9 +835,9 @@ def _to_cwl_tool_object(
def _cwl_tool_object_to_proxy(
cwl_tool: "Process",
- uuid: Union[UUID, str],
+ uuid: UUID | str,
raw_process_reference: Optional["RawProcessReference"] = None,
- tool_path: Optional[str] = None,
+ tool_path: str | None = None,
) -> ToolProxy:
raw_tool = cwl_tool.tool
if "class" not in raw_tool:
@@ -874,7 +869,7 @@ def _schema_loader(strict_cwl_validation: bool):
def _hack_cwl_requirements(cwl_tool):
- move_to_hints: List[int] = []
+ move_to_hints: list[int] = []
for i, requirement in enumerate(cwl_tool.requirements):
if requirement["class"] == DOCKER_REQUIREMENT:
move_to_hints.insert(0, i)
@@ -1267,9 +1262,9 @@ class InputInstance:
def to_dict(self, itemwise: Literal[False]) -> InputInstanceDict: ...
@overload
- def to_dict(self, itemwise: Literal[True]) -> Union[InputInstanceDict, InputInstanceArrayDict]: ...
+ def to_dict(self, itemwise: Literal[True]) -> InputInstanceDict | InputInstanceArrayDict: ...
- def to_dict(self, itemwise: bool = True) -> Union[InputInstanceDict, InputInstanceArrayDict]:
+ def to_dict(self, itemwise: bool = True) -> InputInstanceDict | InputInstanceArrayDict:
if itemwise and self.array:
return InputInstanceArrayDict(
type="repeat", name=f"{self.name}_repeat", title=f"{self.name}", blocks=[self.to_dict(itemwise=False)]
diff --git a/lib/galaxy/tool_util/cwl/representation.py b/lib/galaxy/tool_util/cwl/representation.py
index 7437411ef8e..cbb0d87d0e9 100644
--- a/lib/galaxy/tool_util/cwl/representation.py
+++ b/lib/galaxy/tool_util/cwl/representation.py
@@ -8,7 +8,6 @@ from enum import Enum
from typing import (
Any,
NamedTuple,
- Optional,
)
from galaxy.exceptions import RequestParameterInvalidException
@@ -61,7 +60,7 @@ class TypeRepresentation(NamedTuple):
name: str
galaxy_param_type: Any
label: str
- collection_type: Optional[str]
+ collection_type: str | None
@property
def uses_param(self):
diff --git a/lib/galaxy/tool_util/cwl/runtime_actions.py b/lib/galaxy/tool_util/cwl/runtime_actions.py
index 65f0a470874..0f02eb4b444 100644
--- a/lib/galaxy/tool_util/cwl/runtime_actions.py
+++ b/lib/galaxy/tool_util/cwl/runtime_actions.py
@@ -1,7 +1,6 @@
import json
import os
import shutil
-from typing import Optional
from galaxy.util import safe_makedirs
from .cwltool_deps import ref_resolver
@@ -66,7 +65,7 @@ def _possible_uri_to_path(location):
return path
-def handle_outputs(job_directory: Optional[str] = None):
+def handle_outputs(job_directory: str | None = None):
# Relocate dynamically collected files to pre-determined locations
# registered with ToolOutput objects via from_work_dir handling.
if job_directory is None:
@@ -119,8 +118,7 @@ def handle_outputs(job_directory: Optional[str] = None):
file_description = file_dict_to_description(output)
file_description.write_to(target_path)
- secondary_files = output.get("secondaryFiles", [])
- if secondary_files:
+ if secondary_files := output.get("secondaryFiles", []):
order = []
index_contents = {"order": order}
diff --git a/lib/galaxy/tool_util/cwl/util.py b/lib/galaxy/tool_util/cwl/util.py
index 86748a20e53..25cdd748329 100644
--- a/lib/galaxy/tool_util/cwl/util.py
+++ b/lib/galaxy/tool_util/cwl/util.py
@@ -12,19 +12,15 @@ import tarfile
import tempfile
import urllib.parse
from collections import namedtuple
+from collections.abc import Callable
from typing import (
Any,
BinaryIO,
- Callable,
- Dict,
- List,
- Optional,
- Tuple,
+ Literal,
)
import yaml
from typing_extensions import (
- Literal,
Protocol,
TypedDict,
)
@@ -49,13 +45,13 @@ OutputPropertiesType = TypedDict(
"OutputPropertiesType",
{
"class": str,
- "location": Optional[str],
- "path": Optional[str],
- "listing": Optional[List[Any]],
- "basename": Optional[str],
- "nameroot": Optional[str],
- "nameext": Optional[str],
- "secondaryFiles": List[Any],
+ "location": str | None,
+ "path": str | None,
+ "listing": list[Any] | None,
+ "basename": str | None,
+ "nameroot": str | None,
+ "nameext": str | None,
+ "secondaryFiles": list[Any],
"checksum": str,
"size": int,
},
@@ -64,8 +60,8 @@ OutputPropertiesType = TypedDict(
def output_properties(
- path: Optional[str] = None,
- content: Optional[bytes] = None,
+ path: str | None = None,
+ content: bytes | None = None,
basename=None,
pseudo_location=False,
) -> OutputPropertiesType:
@@ -101,7 +97,7 @@ def _handle_pseudo_location(properties, pseudo_location):
properties["location"] = properties["basename"]
-def abs_path_or_uri(path_or_uri: str, relative_to: str, resolve_data: Optional[Callable[[str], Optional[str]]]) -> str:
+def abs_path_or_uri(path_or_uri: str, relative_to: str, resolve_data: Callable[[str], str | None] | None) -> str:
"""Return the absolute path if this isn't a URI, otherwise keep the URI the same."""
if "://" in path_or_uri:
return path_or_uri
@@ -136,25 +132,24 @@ def path_or_uri_to_uri(path_or_uri: str) -> str:
class CollectionCreateFunc(Protocol):
-
def __call__(
self,
- element_identifiers: List[Dict[str, Any]],
+ element_identifiers: list[dict[str, Any]],
collection_type: str,
- rows: Optional[Dict[str, Any]] = None,
- name: Optional[str] = None,
- ) -> Dict[str, Any]:
+ rows: dict[str, Any] | None = None,
+ name: str | None = None,
+ ) -> dict[str, Any]:
"""Create a collection from these identifiers."""
def galactic_job_json(
- job: Dict[str, Any],
+ job: dict[str, Any],
test_data_directory: str,
- upload_func: Callable[["UploadTarget"], Dict[str, Any]],
+ upload_func: Callable[["UploadTarget"], dict[str, Any]],
collection_create_func: CollectionCreateFunc,
tool_or_workflow: Literal["tool", "workflow"] = "workflow",
- resolve_data: Optional[Callable[[str], Optional[str]]] = None,
-) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
+ resolve_data: Callable[[str], str | None] | None = None,
+) -> tuple[dict[str, Any], list[dict[str, Any]]]:
"""Adapt a CWL job object to the Galaxy API.
CWL derived tools in Galaxy can consume a job description sort of like
@@ -164,10 +159,10 @@ def galactic_job_json(
for Galaxy.
"""
- datasets: List[Dict[str, Any]] = []
- dataset_collections: List[Dict[str, Any]] = []
+ datasets: list[dict[str, Any]] = []
+ dataset_collections: list[dict[str, Any]] = []
- def response_to_hda(target: UploadTarget, upload_response: Dict[str, Any]) -> Dict[str, str]:
+ def response_to_hda(target: UploadTarget, upload_response: dict[str, Any]) -> dict[str, str]:
assert isinstance(upload_response, dict), upload_response
assert "outputs" in upload_response, upload_response
assert len(upload_response["outputs"]) > 0, upload_response
@@ -176,24 +171,24 @@ def galactic_job_json(
dataset_id = dataset["id"]
return {"src": "hda", "id": dataset_id}
- def upload_file(file_path: str, secondary_files: Optional[str], **kwargs) -> Dict[str, str]:
+ def upload_file(file_path: str, secondary_files: str | None, **kwargs) -> dict[str, str]:
file_path = abs_path_or_uri(file_path, test_data_directory, resolve_data=resolve_data)
target = FileUploadTarget(file_path, secondary_files, **kwargs)
upload_response = upload_func(target)
return response_to_hda(target, upload_response)
- def upload_file_literal(contents: str, **kwd) -> Dict[str, str]:
+ def upload_file_literal(contents: str, **kwd) -> dict[str, str]:
target = FileLiteralTarget(contents, **kwd)
upload_response = upload_func(target)
return response_to_hda(target, upload_response)
- def upload_tar(file_path: str, file_type: str = "directory", name: str = "uploaded tar file") -> Dict[str, str]:
+ def upload_tar(file_path: str, file_type: str = "directory", name: str = "uploaded tar file") -> dict[str, str]:
file_path = abs_path_or_uri(file_path, test_data_directory, resolve_data=resolve_data)
target = DirectoryUploadTarget(file_path, file_type=file_type, name=name)
upload_response = upload_func(target)
return response_to_hda(target, upload_response)
- def upload_file_with_composite_data(file_path: Optional[str], composite_data, **kwargs) -> Dict[str, str]:
+ def upload_file_with_composite_data(file_path: str | None, composite_data, **kwargs) -> dict[str, str]:
if file_path is not None:
file_path = abs_path_or_uri(file_path, test_data_directory, resolve_data=resolve_data)
composite_data_resolved = []
@@ -203,7 +198,7 @@ def galactic_job_json(
upload_response = upload_func(target)
return response_to_hda(target, upload_response)
- def upload_object(the_object: Any) -> Dict[str, str]:
+ def upload_object(the_object: Any) -> dict[str, str]:
target = ObjectUploadTarget(the_object)
upload_response = upload_func(target)
return response_to_hda(target, upload_response)
@@ -278,12 +273,11 @@ def galactic_job_json(
return value
- secondary_files = value.get("secondaryFiles", [])
secondary_files_tar_path = None
- if secondary_files:
+ if secondary_files := value.get("secondaryFiles", []):
tmp = tempfile.NamedTemporaryFile(delete=False)
tf = tarfile.open(fileobj=tmp, mode="w:")
- order: List[str] = []
+ order: list[str] = []
index_contents = {"order": order}
for secondary_file in secondary_files:
secondary_file_path = secondary_file.get("location", None) or secondary_file.get("path", None)
@@ -301,7 +295,7 @@ def galactic_job_json(
return upload_file(file_path, secondary_files_tar_path, filetype=filetype, **kwd)
- def replacement_directory(value: Dict[str, Any]) -> Dict[str, Any]:
+ def replacement_directory(value: dict[str, Any]) -> dict[str, Any]:
file_path = value.get("location", None) or value.get("path", None)
if file_path is None:
return value
@@ -316,7 +310,7 @@ def galactic_job_json(
return upload_tar(tmp.name, file_type=file_type, name=os.path.basename(file_path))
- def replacement_list(value) -> Dict[str, str]:
+ def replacement_list(value) -> dict[str, str]:
collection_element_identifiers = []
for i, item in enumerate(value):
dataset = replacement_item(item, force_to_file=True)
@@ -330,7 +324,7 @@ def galactic_job_json(
hdca_id = collection["id"]
return {"src": "hdca", "id": hdca_id}
- def to_elements(value, rank_collection_type: str) -> List[Dict[str, Any]]:
+ def to_elements(value, rank_collection_type: str) -> list[dict[str, Any]]:
collection_element_identifiers = []
assert "elements" in value
elements = value["elements"]
@@ -356,7 +350,7 @@ def galactic_job_json(
return collection_element_identifiers
- def replacement_collection(value: Dict[str, Any]) -> Dict[str, str]:
+ def replacement_collection(value: dict[str, Any]) -> dict[str, str]:
if value.get("galaxy_id"):
return {"src": "hdca", "id": str(value["galaxy_id"])}
assert "collection_type" in value
@@ -429,9 +423,9 @@ class FileLiteralTarget(UploadTarget):
class FileUploadTarget(UploadTarget):
def __init__(
self,
- path: Optional[str],
- secondary_files: Optional[str] = None,
- composite_data: Optional[List[str]] = None,
+ path: str | None,
+ secondary_files: str | None = None,
+ composite_data: list[str] | None = None,
**kwargs,
) -> None:
self.path = path
@@ -446,7 +440,7 @@ class FileUploadTarget(UploadTarget):
class ObjectUploadTarget(UploadTarget):
def __init__(self, the_object: Any) -> None:
self.object = the_object
- self.properties: Dict = {}
+ self.properties: dict = {}
def __str__(self) -> str:
return f"ObjectUploadTarget[object={self.object}] with {self.properties}"
@@ -614,7 +608,7 @@ def output_to_cwl_json(
if not basename:
basename = output_metadata.get("name")
- listing: List[OutputPropertiesType] = []
+ listing: list[OutputPropertiesType] = []
properties = {
"class": "Directory",
"basename": basename,
diff --git a/lib/galaxy/tool_util/data/__init__.py b/lib/galaxy/tool_util/data/__init__.py
index bbf64ed1c1a..603ae29934e 100644
--- a/lib/galaxy/tool_util/data/__init__.py
+++ b/lib/galaxy/tool_util/data/__init__.py
@@ -15,20 +15,14 @@ import os.path
import re
import string
import time
+from collections.abc import Callable
from dataclasses import dataclass
from glob import glob
from tempfile import NamedTemporaryFile
from typing import (
Any,
BinaryIO,
- Callable,
- Dict,
- List,
- Optional,
overload,
- Set,
- Tuple,
- Type,
TYPE_CHECKING,
Union,
)
@@ -77,11 +71,11 @@ TOOL_DATA_TABLE_CONF_XML = """
# Internally just the first two - but tool shed code (data_manager_manual) will still
# pass DataManager in.
-EntrySource = Optional[Union[dict, RepoInfo, "DataManager"]]
+EntrySource = Union[dict, RepoInfo, "DataManager"] | None
class StoresConfigFilePaths(Protocol):
- def get(self, key: Any, default: Optional[Any]) -> Optional[Any]: ...
+ def get(self, key: Any, default: Any | None) -> Any | None: ...
class ToolDataPathFiles:
@@ -92,7 +86,7 @@ class ToolDataPathFiles:
self.update_time = 0
@property
- def tool_data_path_files(self) -> Set[str]:
+ def tool_data_path_files(self) -> set[str]:
if time.time() - self.update_time > 1:
self.update_files()
return self._tool_data_path_files
@@ -124,26 +118,26 @@ class ToolDataPathFiles:
return os.path.exists(path)
-ErrorListT = List[str]
+ErrorListT = list[str]
class FileNameInfoT(TypedDict):
found: bool
filename: str
from_shed_config: bool
- tool_data_path: Optional[StrPath]
- config_element: Optional[Element]
- tool_shed_repository: Optional[Dict[str, Any]]
+ tool_data_path: StrPath | None
+ config_element: Element | None
+ tool_shed_repository: dict[str, Any] | None
errors: ErrorListT
-LoadInfoT = Tuple[Tuple[Element, Optional[StrPath]], Dict[str, Any]]
+LoadInfoT = tuple[tuple[Element, StrPath | None], dict[str, Any]]
class DataTableColumnMismatch(Exception):
"""Two data tables share a name but declare different columns."""
- def __init__(self, table_name: str, existing_columns: Dict[str, int], incoming_columns: Dict[str, int]):
+ def __init__(self, table_name: str, existing_columns: dict[str, int], incoming_columns: dict[str, int]):
self.table_name = table_name
self.existing_columns = existing_columns
self.incoming_columns = incoming_columns
@@ -155,12 +149,12 @@ class DataTableColumnMismatch(Exception):
class ToolDataTable(Dictifiable):
type_key: str
- data: List[List[str]]
+ data: list[list[str]]
empty_field_value: str
- empty_field_values: Dict[Optional[str], str]
- filenames: Dict[str, FileNameInfoT]
+ empty_field_values: dict[str | None, str]
+ filenames: dict[str, FileNameInfoT]
_load_info: LoadInfoT
- _merged_load_info: List[Tuple[Type["ToolDataTable"], LoadInfoT]]
+ _merged_load_info: list[tuple[type["ToolDataTable"], LoadInfoT]]
@classmethod
def from_dict(cls, d):
@@ -175,24 +169,24 @@ class ToolDataTable(Dictifiable):
def __init__(
self,
config_element: Element,
- tool_data_path: Optional[StrPath],
+ tool_data_path: StrPath | None,
tool_data_path_files: ToolDataPathFiles,
from_shed_config: bool = False,
- filename: Optional[StrPath] = None,
- other_config_dict: Optional[StoresConfigFilePaths] = None,
+ filename: StrPath | None = None,
+ other_config_dict: StoresConfigFilePaths | None = None,
) -> None:
name = config_element.get("name")
assert name
self.name = name
self.empty_field_value = config_element.get("empty_field_value", "")
- self.empty_field_values: Dict[str, str] = {}
+ self.empty_field_values: dict[str, str] = {}
self.allow_duplicate_entries = util.asbool(config_element.get("allow_duplicate_entries", True))
self.here = os.path.dirname(filename) if filename else None
- self.filenames: Dict[str, FileNameInfoT] = {}
+ self.filenames: dict[str, FileNameInfoT] = {}
self.tool_data_path = tool_data_path
self.tool_data_path_files = tool_data_path_files
self.other_config_dict = other_config_dict or {}
- self.missing_index_file: Optional[str] = None
+ self.missing_index_file: str | None = None
# increment this variable any time a new entry is added, or when the table is totally reloaded
# This value has no external meaning, and does not represent an abstract version of the underlying data
self._loaded_content_version = 1
@@ -205,25 +199,25 @@ class ToolDataTable(Dictifiable):
"filename": filename,
},
)
- self._merged_load_info: List[Tuple[Type[ToolDataTable], Tuple[Tuple[Element, StrPath], Dict[str, Any]]]] = []
+ self._merged_load_info: list[tuple[type[ToolDataTable], tuple[tuple[Element, StrPath], dict[str, Any]]]] = []
- def _update_version(self, version: Optional[int] = None) -> int:
+ def _update_version(self, version: int | None = None) -> int:
if version is not None:
self._loaded_content_version = version
else:
self._loaded_content_version += 1
return self._loaded_content_version
- def get_empty_field_by_name(self, name: Optional[str]) -> str:
+ def get_empty_field_by_name(self, name: str | None) -> str:
return self.empty_field_values.get(name, self.empty_field_value)
def _add_entry(
self,
- entry: Union[List[str], Dict[str, str]],
+ entry: list[str] | dict[str, str],
allow_duplicates: bool = True,
persist: bool = False,
entry_source: EntrySource = None,
- tool_data_file_path: Optional[str] = None,
+ tool_data_file_path: str | None = None,
bundle_mode: bool = False,
**kwd,
) -> None:
@@ -231,11 +225,11 @@ class ToolDataTable(Dictifiable):
def add_entry(
self,
- entry: Union[List[str], Dict[str, str]],
+ entry: list[str] | dict[str, str],
allow_duplicates: bool = True,
persist: bool = False,
entry_source: EntrySource = None,
- tool_data_file_path: Optional[str] = None,
+ tool_data_file_path: str | None = None,
bundle_mode: bool = False,
**kwd,
) -> int:
@@ -252,7 +246,7 @@ class ToolDataTable(Dictifiable):
def add_entries(
self,
- entries: List[List[str]],
+ entries: list[list[str]],
allow_duplicates: bool = True,
persist: bool = False,
entry_source: EntrySource = None,
@@ -325,11 +319,11 @@ class TabularToolDataTable(ToolDataTable):
def __init__(
self,
config_element: Element,
- tool_data_path: Optional[StrPath],
+ tool_data_path: StrPath | None,
tool_data_path_files: ToolDataPathFiles,
from_shed_config: bool = False,
- filename: Optional[StrPath] = None,
- other_config_dict: Optional[StoresConfigFilePaths] = None,
+ filename: StrPath | None = None,
+ other_config_dict: StoresConfigFilePaths | None = None,
) -> None:
super().__init__(
config_element,
@@ -346,7 +340,7 @@ class TabularToolDataTable(ToolDataTable):
def configure_and_load(
self,
config_element: Element,
- tool_data_path: Optional[StrPath],
+ tool_data_path: StrPath | None,
from_shed_config: bool = False,
url_timeout: float = 10,
) -> None:
@@ -359,8 +353,7 @@ class TabularToolDataTable(ToolDataTable):
self.parse_column_spec(config_element)
# store repo info if available:
- repo_elem = config_element.find("tool_shed_repository")
- if repo_elem is not None:
+ if (repo_elem := config_element.find("tool_shed_repository")) is not None:
tool_shed_elem = repo_elem.find("tool_shed")
assert tool_shed_elem is not None
repository_name_elem = repo_elem.find("repository_name")
@@ -500,7 +493,7 @@ class TabularToolDataTable(ToolDataTable):
self.extend_data_with(filename)
# This method is used in tools, so need to keep its API stable
- def get_fields(self) -> List[List[str]]:
+ def get_fields(self) -> list[list[str]]:
return self.data.copy()
def get_field(self, value):
@@ -511,7 +504,7 @@ class TabularToolDataTable(ToolDataTable):
return rval
# This method is used in tools, so need to keep its API stable
- def get_named_fields_list(self) -> List[Dict[Union[str, int], str]]:
+ def get_named_fields_list(self) -> list[dict[str | int, str]]:
rval = []
named_columns = self.get_column_name_list()
for fields in self.get_fields():
@@ -519,7 +512,7 @@ class TabularToolDataTable(ToolDataTable):
for i, field in enumerate(fields):
if i == len(named_columns):
break
- field_name: Optional[Union[str, int]] = named_columns[i]
+ field_name: str | int | None = named_columns[i]
if field_name is None:
field_name = i # check that this is supposed to be 0 based.
field_dict[field_name] = field
@@ -532,16 +525,15 @@ class TabularToolDataTable(ToolDataTable):
@staticmethod
def parse_column_spec_element(
config_element: Element,
- ) -> Tuple[Dict[str, int], int, Dict[str, str]]:
+ ) -> tuple[dict[str, int], int, dict[str, str]]:
"""
Parse column definitions into ``(columns, largest_index, empty_field_values)``.
Does not mutate or assert — callers layer their own validation.
"""
- columns: Dict[str, int] = {}
- empty_field_values: Dict[str, str] = {}
+ columns: dict[str, int] = {}
+ empty_field_values: dict[str, str] = {}
largest_index = 0
- columns_elem = config_element.find("columns")
- if columns_elem is not None:
+ if (columns_elem := config_element.find("columns")) is not None:
column_names = util.xml_text(columns_elem)
for index, name in enumerate(n.strip() for n in column_names.split(",")):
columns[name] = index
@@ -578,15 +570,15 @@ class TabularToolDataTable(ToolDataTable):
self.empty_field_values.update(parsed_empty_field_values)
assert "value" in self.columns, "Required 'value' column missing from column def"
- def extend_data_with(self, filename: str, errors: Optional[ErrorListT] = None) -> None:
+ def extend_data_with(self, filename: str, errors: ErrorListT | None = None) -> None:
here = os.path.dirname(os.path.abspath(filename))
self.data.extend(self.parse_file_fields(filename, errors=errors, here=here))
if not self.allow_duplicate_entries:
self._deduplicate_data()
def parse_file_fields(
- self, filename: str, errors: Optional[ErrorListT] = None, here: str = "__HERE__"
- ) -> List[List[str]]:
+ self, filename: str, errors: ErrorListT | None = None, here: str = "__HERE__"
+ ) -> list[list[str]]:
"""
Parse separated lines from file and return a list of tuples.
@@ -613,8 +605,8 @@ class TabularToolDataTable(ToolDataTable):
return rval
# This method is used in tools, so need to keep its API stable
- def get_column_name_list(self) -> List[Union[str, None]]:
- rval: List[Union[str, None]] = []
+ def get_column_name_list(self) -> list[str | None]:
+ rval: list[str | None] = []
for i in range(self.largest_index + 1):
found_column = False
for name, index in self.columns.items():
@@ -639,7 +631,7 @@ class TabularToolDataTable(ToolDataTable):
return rval[0]
return default
- def get_entries(self, query_attr: str, query_val: str, return_attr: str, limit=None) -> List:
+ def get_entries(self, query_attr: str, query_val: str, return_attr: str, limit=None) -> list:
"""
Returns table entries associated with a col/val pair.
"""
@@ -666,15 +658,15 @@ class TabularToolDataTable(ToolDataTable):
return rval
# This method is used in tools, so need to keep its API stable
- def get_filename_for_source(self, source: EntrySource, default: Optional[str] = None) -> Optional[str]:
- source_repo_info: Optional[dict] = None
+ def get_filename_for_source(self, source: EntrySource, default: str | None = None) -> str | None:
+ source_repo_info: dict | None = None
if source:
# if dict, assume is compatible info dict, otherwise call method
if isinstance(source, dict):
source_repo_info = source
else:
- source_repo_info_model: Optional[RepoInfo]
+ source_repo_info_model: RepoInfo | None
if source is None or isinstance(source, RepoInfo):
source_repo_info_model = source
else:
@@ -682,7 +674,7 @@ class TabularToolDataTable(ToolDataTable):
source_repo_info_model = source.repo_info
source_repo_info = source_repo_info_model.model_dump() if source_repo_info_model else None
filename = default
- shared_fallback: Optional[str] = None
+ shared_fallback: str | None = None
for name, value in self.filenames.items():
repo_info = value.get("tool_shed_repository")
if (not source_repo_info and not repo_info) or (
@@ -702,11 +694,11 @@ class TabularToolDataTable(ToolDataTable):
def _add_entry(
self,
- entry: Union[List[str], Dict[str, str]],
+ entry: list[str] | dict[str, str],
allow_duplicates: bool = True,
persist: bool = False,
entry_source: EntrySource = None,
- tool_data_file_path: Optional[str] = None,
+ tool_data_file_path: str | None = None,
bundle_mode: bool = False,
**kwd,
) -> None:
@@ -771,7 +763,7 @@ class TabularToolDataTable(ToolDataTable):
def append_entries_with_attribution(
self,
- entries: List[List[str]],
+ entries: list[list[str]],
attribution: str,
allow_duplicates: bool = False,
) -> int:
@@ -782,7 +774,7 @@ class TabularToolDataTable(ToolDataTable):
batch. Writes a single ``{comment_char} {attribution}`` line before the first
new row. No-op if no rows survive the dedup.
"""
- filename: Optional[str] = self.get_filename_for_source(None)
+ filename: str | None = self.get_filename_for_source(None)
if filename is None:
for name in self.filenames:
filename = name
@@ -790,10 +782,10 @@ class TabularToolDataTable(ToolDataTable):
if filename is None:
raise MessageException(f"Unable to determine filename for appending entries to data table '{self.name}'.")
value_index = self.columns.get("value", 0)
- existing_values: Optional[Set[str]] = None
+ existing_values: set[str] | None = None
if not allow_duplicates:
existing_values = {row[value_index] for row in self.data if value_index < len(row)}
- new_rows: List[List[str]] = []
+ new_rows: list[list[str]] = []
for entry in entries:
fields = self._replace_field_separators(list(entry))
if self.largest_index >= len(fields):
@@ -911,7 +903,7 @@ class TabularToolDataTable(ToolDataTable):
def xml_string(self):
return util.xml_to_string(self.config_element)
- def to_dict(self, view: str = "collection", value_mapper: Optional[Dict[str, Callable]] = None) -> Dict[str, Any]:
+ def to_dict(self, view: str = "collection", value_mapper: dict[str, Callable] | None = None) -> dict[str, Any]:
rval = super().to_dict(view, value_mapper)
if view == "element":
rval["columns"] = sorted(self.columns.keys(), key=lambda x: self.columns[x])
@@ -920,9 +912,9 @@ class TabularToolDataTable(ToolDataTable):
class TabularToolDataField(Dictifiable):
- dict_collection_visible_keys: List[str] = []
+ dict_collection_visible_keys: list[str] = []
- def __init__(self, data: Dict):
+ def __init__(self, data: dict):
self.data = data
def __getitem__(self, key):
@@ -960,7 +952,7 @@ class TabularToolDataField(Dictifiable):
sha1.update(util.smart_str(fmap[k]))
return sha1.hexdigest()
- def to_dict(self, view: str = "collection", value_mapper: Optional[Dict[str, Callable]] = None) -> Dict[str, Any]:
+ def to_dict(self, view: str = "collection", value_mapper: dict[str, Callable] | None = None) -> dict[str, Any]:
rval = super().to_dict(view, value_mapper)
rval["name"] = self.data["value"]
rval["fields"] = self.data
@@ -971,21 +963,21 @@ class TabularToolDataField(Dictifiable):
@overload
-def _expand_here_template(content: str, here: Optional[str]) -> str: ...
+def _expand_here_template(content: str, here: str | None) -> str: ...
@overload
-def _expand_here_template(content: None, here: Optional[str]) -> None: ...
+def _expand_here_template(content: None, here: str | None) -> None: ...
-def _expand_here_template(content: Optional[str], here: Optional[str]) -> Optional[str]:
+def _expand_here_template(content: str | None, here: str | None) -> str | None:
if here and content:
content = string.Template(content).safe_substitute({"__HERE__": here})
return content
# Registry of tool data types by type_key
-tool_data_table_types_list: List[Type[ToolDataTable]] = [TabularToolDataTable]
+tool_data_table_types_list: list[type[ToolDataTable]] = [TabularToolDataTable]
class HasExtraFiles(Protocol):
@@ -1011,15 +1003,15 @@ class OutputDataset(HasExtraFiles, Protocol):
class ToolDataTableManager(Dictifiable):
"""Manages a collection of tool data tables"""
- data_tables: Dict[str, ToolDataTable]
+ data_tables: dict[str, ToolDataTable]
tool_data_table_types = {cls.type_key: cls for cls in tool_data_table_types_list}
def __init__(
self,
tool_data_path: str,
- config_filename: Optional[Union[StrPath, List[StrPath]]] = None,
+ config_filename: StrPath | list[StrPath] | None = None,
tool_data_table_config_path_set=None,
- other_config_dict: Optional[StoresConfigFilePaths] = None,
+ other_config_dict: StoresConfigFilePaths | None = None,
) -> None:
self.tool_data_path = tool_data_path
# This stores all defined data table entries from both the tool_data_table_conf.xml file and the shed_tool_data_table_conf.xml file
@@ -1055,24 +1047,23 @@ class ToolDataTableManager(Dictifiable):
def set(self, name: str, value: ToolDataTable) -> None:
self[name] = value
- def get_tables(self) -> Dict[str, "ToolDataTable"]:
+ def get_tables(self) -> dict[str, "ToolDataTable"]:
return self.data_tables
def assert_data_table_consistency(
self,
candidate_name: str,
- candidate_columns: Dict[str, int],
+ candidate_columns: dict[str, int],
) -> None:
"""Raise if ``candidate_name`` is already registered with different columns."""
- existing = self.data_tables.get(candidate_name)
- if existing is not None:
+ if (existing := self.data_tables.get(candidate_name)) is not None:
existing_columns = getattr(existing, "columns", None)
if existing_columns is not None and existing_columns != candidate_columns:
raise DataTableColumnMismatch(candidate_name, existing_columns, candidate_columns)
def to_dict(
- self, view: str = "collection", value_mapper: Optional[Dict[str, Callable]] = None
- ) -> Dict[str, Dict[str, Any]]:
+ self, view: str = "collection", value_mapper: dict[str, Callable] | None = None
+ ) -> dict[str, dict[str, Any]]:
return {
name: data_table.to_dict(view="export", value_mapper=value_mapper)
for name, data_table in self.data_tables.items()
@@ -1083,8 +1074,8 @@ class ToolDataTableManager(Dictifiable):
out.write(json.dumps(self.to_dict()))
def load_from_config_file(
- self, config_filename: StrPath, tool_data_path: Optional[StrPath], from_shed_config: bool = False
- ) -> List[Element]:
+ self, config_filename: StrPath, tool_data_path: StrPath | None, from_shed_config: bool = False
+ ) -> list[Element]:
"""
This method is called under 3 conditions:
@@ -1125,11 +1116,11 @@ class ToolDataTableManager(Dictifiable):
def from_elem(
self,
table_elem: Element,
- tool_data_path: Optional[StrPath],
+ tool_data_path: StrPath | None,
from_shed_config: bool,
filename: StrPath,
tool_data_path_files: ToolDataPathFiles,
- other_config_dict: Optional[StoresConfigFilePaths] = None,
+ other_config_dict: StoresConfigFilePaths | None = None,
) -> ToolDataTable:
table_type = table_elem.get("type", "tabular")
assert table_type in self.tool_data_table_types, f"Unknown data table type '{table_type}'"
@@ -1145,10 +1136,10 @@ class ToolDataTableManager(Dictifiable):
def add_new_entries_from_config_file(
self,
config_filename: StrPath,
- tool_data_path: Optional[StrPath],
+ tool_data_path: StrPath | None,
shed_tool_data_table_config: StrPath,
persist: bool = False,
- ) -> Tuple[List[Element], str]:
+ ) -> tuple[list[Element], str]:
"""
This method is called when a tool shed repository that includes a tool_data_table_conf.xml.sample file is being
installed into a local galaxy instance. We have 2 cases to handle, files whose root tag is , for example::
@@ -1189,8 +1180,8 @@ class ToolDataTableManager(Dictifiable):
def to_xml_file(
self,
shed_tool_data_table_config: StrPath,
- new_elems: Optional[List[Element]] = None,
- remove_elems: Optional[List[Element]] = None,
+ new_elems: list[Element] | None = None,
+ remove_elems: list[Element] | None = None,
) -> None:
"""
Write the current in-memory version of the shed_tool_data_table_conf.xml file to disk.
@@ -1234,9 +1225,7 @@ class ToolDataTableManager(Dictifiable):
if out_path_is_new:
self.tool_data_path_files.update_files()
- def reload_tables(
- self, table_names: Optional[Union[List[str], str]] = None, path: Optional[str] = None
- ) -> List[str]:
+ def reload_tables(self, table_names: list[str] | str | None = None, path: str | None = None) -> list[str]:
"""
Reload tool data tables. If neither table_names nor path is given, reloads all tool data tables.
"""
@@ -1253,7 +1242,7 @@ class ToolDataTableManager(Dictifiable):
log.debug("Reloaded tool data table '%s' from files.", table_name)
return table_names
- def get_table_names_by_path(self, path: str) -> List[str]:
+ def get_table_names_by_path(self, path: str) -> list[str]:
"""Returns a list of table names given a path"""
table_names = set()
for name, data_table in self.data_tables.items():
@@ -1263,12 +1252,12 @@ class ToolDataTableManager(Dictifiable):
def process_bundle(
self,
- out_data: Dict[str, OutputDataset],
+ out_data: dict[str, OutputDataset],
bundle_description: DataTableBundleProcessorDescription,
- repo_info: Optional[RepoInfo],
+ repo_info: RepoInfo | None,
options: "BundleProcessingOptions",
- ) -> List[str]:
- data_manager_dict: Dict[str, Any] = _data_manager_dict(out_data)
+ ) -> list[str]:
+ data_manager_dict: dict[str, Any] = _data_manager_dict(out_data)
bundle = DataTableBundle(
processor_description=bundle_description,
data_tables=data_manager_dict.get("data_tables", {}),
@@ -1280,7 +1269,7 @@ class ToolDataTableManager(Dictifiable):
self,
target: str,
options: "BundleProcessingOptions",
- ) -> List[str]:
+ ) -> list[str]:
if not os.path.isdir(target):
target_directory = decompress_path_to_directory(target)
else:
@@ -1295,13 +1284,13 @@ class ToolDataTableManager(Dictifiable):
def write_bundle(
self,
- out_data: Dict[str, OutputDataset],
+ out_data: dict[str, OutputDataset],
bundle_description: DataTableBundleProcessorDescription,
- repo_info: Optional[RepoInfo],
- ) -> Dict[str, OutputDataset]:
+ repo_info: RepoInfo | None,
+ ) -> dict[str, OutputDataset]:
"""Writes bundle and returns bundle path."""
data_manager_dict = _data_manager_dict(out_data, ensure_single_output=True)
- bundle_datasets: Dict[str, OutputDataset] = {}
+ bundle_datasets: dict[str, OutputDataset] = {}
for output_name, dataset in out_data.items():
if dataset.ext != "data_manager_json":
continue
@@ -1328,11 +1317,11 @@ class BundleProcessingOptions:
what: str
data_manager_path: str
target_config_file: str
- tool_data_file_path: Optional[str] = None
+ tool_data_file_path: str | None = None
-def _data_manager_dict(out_data: Dict[str, OutputDataset], ensure_single_output: bool = False) -> Dict[str, Any]:
- data_manager_dict: Dict[str, Any] = {}
+def _data_manager_dict(out_data: dict[str, OutputDataset], ensure_single_output: bool = False) -> dict[str, Any]:
+ data_manager_dict: dict[str, Any] = {}
found_output = False
for output_name, output_dataset in out_data.items():
@@ -1355,7 +1344,7 @@ def _data_manager_dict(out_data: Dict[str, OutputDataset], ensure_single_output:
return data_manager_dict
-from typing import Mapping
+from collections.abc import Mapping
def _process_bundle(
diff --git a/lib/galaxy/tool_util/data/_schema.py b/lib/galaxy/tool_util/data/_schema.py
index eb89491e7d8..74a63c4b6d0 100644
--- a/lib/galaxy/tool_util/data/_schema.py
+++ b/lib/galaxy/tool_util/data/_schema.py
@@ -1,9 +1,3 @@
-from typing import (
- Dict,
- List,
- Optional,
-)
-
from pydantic import (
BaseModel,
ConfigDict,
@@ -32,11 +26,11 @@ class ToolDataEntry(Model):
class ToolDataEntryList(RootModel):
- root: List[ToolDataEntry] = Field(
+ root: list[ToolDataEntry] = Field(
title="A list with details on individual data tables.",
)
- def find_entry(self, name: str) -> Optional[ToolDataEntry]:
+ def find_entry(self, name: str) -> ToolDataEntry | None:
for entry in self.root:
if entry.name == name:
return entry
@@ -44,7 +38,7 @@ class ToolDataEntryList(RootModel):
class ToolDataDetails(ToolDataEntry):
- columns: List[str] = Field(
+ columns: list[str] = Field(
..., # Mark this field as required
title="Columns",
description="A list of column names",
@@ -52,7 +46,7 @@ class ToolDataDetails(ToolDataEntry):
)
# We must use an alias since the name 'fields'
# shadows a Model attribute
- fields_value: List[List[str]] = Field(
+ fields_value: list[list[str]] = Field(
alias="fields",
default=[],
title="Fields",
@@ -74,18 +68,18 @@ class ToolDataField(Model):
)
# We must use an alias since the name 'fields'
# shadows a Model attribute
- fields_value: Dict[str, str] = Field(
+ fields_value: dict[str, str] = Field(
..., # Mark this field as required
alias="fields",
title="Fields",
description="", # TODO add documentation
)
- base_dir: List[str] = Field(
+ base_dir: list[str] = Field(
..., # Mark this field as required
title="Base directories",
description="A list of directories where the data files are stored",
)
- files: Dict[str, int] = Field(
+ files: dict[str, int] = Field(
..., # Mark this field as required
title="Files",
description="A dictionary of file names and their size in bytes",
diff --git a/lib/galaxy/tool_util/data/bundles/models.py b/lib/galaxy/tool_util/data/bundles/models.py
index 730c51c216f..210e39418c1 100644
--- a/lib/galaxy/tool_util/data/bundles/models.py
+++ b/lib/galaxy/tool_util/data/bundles/models.py
@@ -1,12 +1,7 @@
import os
-from typing import (
+from collections.abc import (
Callable,
- Dict,
Iterator,
- List,
- Optional,
- Tuple,
- Union,
)
from pydantic import (
@@ -21,7 +16,7 @@ from galaxy.util import (
)
DEFAULT_VALUE_TRANSLATION_TYPE = "template"
-VALUE_TRANSLATION_FUNCTIONS: Dict[str, Callable] = dict(abspath=os.path.abspath)
+VALUE_TRANSLATION_FUNCTIONS: dict[str, Callable] = dict(abspath=os.path.abspath)
DEFAULT_VALUE_TRANSLATION_TYPE = "template"
@@ -33,10 +28,10 @@ class DataTableBundleProcessorDataTableOutputColumnTranslation(BaseModel):
class DataTableBundleProcessorDataTableOutputColumnMove(BaseModel):
type: str
- source_base: Optional[str] = None
+ source_base: str | None = None
source_value: str = ""
- target_base: Optional[str] = None
- target_value: Optional[str] = None
+ target_base: str | None = None
+ target_value: str | None = None
relativize_symlinks: bool
model_config = ConfigDict(extra="forbid")
@@ -44,9 +39,9 @@ class DataTableBundleProcessorDataTableOutputColumnMove(BaseModel):
class DataTableBundleProcessorDataTableOutputColumn(BaseModel):
name: str
data_table_name: str
- output_ref: Optional[str] = None
- value_translations: List[DataTableBundleProcessorDataTableOutputColumnTranslation] = []
- moves: List[DataTableBundleProcessorDataTableOutputColumnMove] = []
+ output_ref: str | None = None
+ value_translations: list[DataTableBundleProcessorDataTableOutputColumnTranslation] = []
+ moves: list[DataTableBundleProcessorDataTableOutputColumnMove] = []
model_config = ConfigDict(extra="forbid")
@model_validator(mode="before")
@@ -59,30 +54,30 @@ class DataTableBundleProcessorDataTableOutputColumn(BaseModel):
class DataTableBundleProcessorDataTableOutput(BaseModel):
- columns: List[DataTableBundleProcessorDataTableOutputColumn]
+ columns: list[DataTableBundleProcessorDataTableOutputColumn]
model_config = ConfigDict(extra="forbid")
class DataTableBundleProcessorDataTable(BaseModel):
name: str
- output: Optional[DataTableBundleProcessorDataTableOutput] = None
+ output: DataTableBundleProcessorDataTableOutput | None = None
model_config = ConfigDict(extra="forbid")
class DataTableBundleProcessorDescription(BaseModel):
undeclared_tables: bool = False
- data_tables: List[DataTableBundleProcessorDataTable]
+ data_tables: list[DataTableBundleProcessorDataTable]
model_config = ConfigDict(extra="forbid")
@property
- def data_table_names(self) -> List[str]:
+ def data_table_names(self) -> list[str]:
names = []
for data_table in self.data_tables:
data_table_name = data_table.name
names.append(data_table_name)
return names
- def _walk_columns(self) -> Iterator[Tuple[str, DataTableBundleProcessorDataTableOutputColumn]]:
+ def _walk_columns(self) -> Iterator[tuple[str, DataTableBundleProcessorDataTableOutputColumn]]:
for data_table in self.data_tables:
data_table_name = data_table.name
output = data_table.output
@@ -91,8 +86,8 @@ class DataTableBundleProcessorDescription(BaseModel):
yield (data_table_name, column)
@property
- def output_ref_by_data_table(self) -> Dict[str, Dict[str, str]]:
- output_refs: Dict[str, Dict[str, str]] = {}
+ def output_ref_by_data_table(self) -> dict[str, dict[str, str]]:
+ output_refs: dict[str, dict[str, str]] = {}
for data_table_name, column in self._walk_columns():
data_table_column_name = column.data_table_name
output_ref = column.output_ref
@@ -103,8 +98,8 @@ class DataTableBundleProcessorDescription(BaseModel):
return output_refs
@property
- def move_by_data_table_column(self) -> Dict[str, Dict[str, DataTableBundleProcessorDataTableOutputColumnMove]]:
- by_column: Dict[str, Dict[str, DataTableBundleProcessorDataTableOutputColumnMove]] = {}
+ def move_by_data_table_column(self) -> dict[str, dict[str, DataTableBundleProcessorDataTableOutputColumnMove]]:
+ by_column: dict[str, dict[str, DataTableBundleProcessorDataTableOutputColumnMove]] = {}
for data_table_name, column in self._walk_columns():
data_table_column_name = column.data_table_name
for move in column.moves:
@@ -115,8 +110,8 @@ class DataTableBundleProcessorDescription(BaseModel):
return by_column
@property
- def value_translation_by_data_table_column(self) -> Dict[str, Dict[str, List[Union[str, Callable]]]]:
- by_column: Dict[str, Dict[str, List[Union[str, Callable]]]] = {}
+ def value_translation_by_data_table_column(self) -> dict[str, dict[str, list[str | Callable]]]:
+ by_column: dict[str, dict[str, list[str | Callable]]] = {}
for data_table_name, column in self._walk_columns():
data_table_column_name = column.data_table_name
for value_translation_model in column.value_translations:
@@ -126,7 +121,7 @@ class DataTableBundleProcessorDescription(BaseModel):
by_column[data_table_name] = {}
if data_table_column_name not in by_column[data_table_name]:
by_column[data_table_name][data_table_column_name] = []
- value_translation: Union[str, Callable]
+ value_translation: str | Callable
if value_translation_type == "function":
if value_translation_str in VALUE_TRANSLATION_FUNCTIONS:
value_translation = VALUE_TRANSLATION_FUNCTIONS[value_translation_str]
@@ -152,8 +147,8 @@ class RepoInfo(BaseModel):
class DataTableBundle(BaseModel):
processor_description: DataTableBundleProcessorDescription
data_tables: dict
- output_name: Optional[str] = None
- repo_info: Optional[RepoInfo] = None
+ output_name: str | None = None
+ repo_info: RepoInfo | None = None
def _xml_to_data_table_output_column_move(move_elem: Element) -> DataTableBundleProcessorDataTableOutputColumnMove:
@@ -171,7 +166,7 @@ def _xml_to_data_table_output_column_move(move_elem: Element) -> DataTableBundle
target_elem = move_elem.find("target")
if target_elem is None:
target_base = None
- target_value: Optional[str] = ""
+ target_value: str | None = ""
else:
target_base = target_elem.get("base", None)
target_value = target_elem.text
@@ -187,9 +182,8 @@ def _xml_to_data_table_output_column_move(move_elem: Element) -> DataTableBundle
def _xml_to_data_table_output_column_translation(
value_translation_elem: Element,
-) -> Optional[DataTableBundleProcessorDataTableOutputColumnTranslation]:
- value_translation = value_translation_elem.text
- if value_translation is not None:
+) -> DataTableBundleProcessorDataTableOutputColumnTranslation | None:
+ if (value_translation := value_translation_elem.text) is not None:
value_translation_type = value_translation_elem.get("type", DEFAULT_VALUE_TRANSLATION_TYPE)
return DataTableBundleProcessorDataTableOutputColumnTranslation(
value=value_translation, type=value_translation_type
@@ -225,7 +219,7 @@ def _xml_to_data_table_output_column(column_elem: Element) -> DataTableBundlePro
)
-def _xml_to_data_table_output(output_elem: Optional[Element]) -> Optional[DataTableBundleProcessorDataTableOutput]:
+def _xml_to_data_table_output(output_elem: Element | None) -> DataTableBundleProcessorDataTableOutput | None:
if output_elem is not None:
columns = []
for column_elem in output_elem.findall("column"):
diff --git a/lib/galaxy/tool_util/deps/__init__.py b/lib/galaxy/tool_util/deps/__init__.py
index 386e3864235..4799f4e7549 100644
--- a/lib/galaxy/tool_util/deps/__init__.py
+++ b/lib/galaxy/tool_util/deps/__init__.py
@@ -8,10 +8,7 @@ import os.path
import shutil
from typing import (
Any,
- Dict,
- List,
Optional,
- Type,
TYPE_CHECKING,
)
@@ -45,10 +42,10 @@ CONFIG_VAL_NOT_FOUND = object()
def build_dependency_manager(
- app_config_dict: Optional[Dict[str, Any]] = None,
- resolution_config_dict: Optional[Dict[str, Any]] = None,
- conf_file: Optional[str] = None,
- default_tool_dependency_dir: Optional[str] = None,
+ app_config_dict: dict[str, Any] | None = None,
+ resolution_config_dict: dict[str, Any] | None = None,
+ conf_file: str | None = None,
+ default_tool_dependency_dir: str | None = None,
) -> "DependencyManager":
"""Build a DependencyManager object from app and/or resolution config.
@@ -101,11 +98,11 @@ def build_dependency_manager(
ContainerType = str
DestinationId = str
-DestinationParametersType = Dict[str, Any]
+DestinationParametersType = dict[str, Any]
class DestinationProtocol(Protocol):
- id: Optional[DestinationId]
+ id: DestinationId | None
params: DestinationParametersType
@@ -121,11 +118,11 @@ class DependencyManager:
dependency available in the current shell environment.
"""
- _destination_for_container_type: Dict[ContainerType, List[DestinationProtocol]]
+ _destination_for_container_type: dict[ContainerType, list[DestinationProtocol]]
cached = False
def __init__(
- self, default_base_path: str, conf_file: Optional[str] = None, app_config: Optional[Dict[str, Any]] = None
+ self, default_base_path: str, conf_file: str | None = None, app_config: dict[str, Any] | None = None
) -> None:
"""
Create a new dependency manager looking for packages under the paths listed
@@ -148,11 +145,11 @@ class DependencyManager:
else:
plugin_source = self.__build_dependency_resolvers_plugin_source(conf_file)
self.dependency_resolvers = self.__parse_resolver_conf_plugins(plugin_source)
- self._enabled_container_types: List[str] = []
+ self._enabled_container_types: list[str] = []
self._destination_for_container_type = {}
def set_enabled_container_types(
- self, container_types_to_destinations: Dict[ContainerType, List[DestinationProtocol]]
+ self, container_types_to_destinations: dict[ContainerType, list[DestinationProtocol]]
):
"""Set the union of all enabled container types."""
self._enabled_container_types = list(container_types_to_destinations.keys())
@@ -160,8 +157,8 @@ class DependencyManager:
self._destination_for_container_type = container_types_to_destinations
def get_destination_info_for_container_type(
- self, container_type: ContainerType, destination_id: Optional[DestinationId] = None
- ) -> Optional[DestinationParametersType]:
+ self, container_type: ContainerType, destination_id: DestinationId | None = None
+ ) -> DestinationParametersType | None:
if destination_id is None:
return next(iter(self._destination_for_container_type[container_type])).params
else:
@@ -204,7 +201,7 @@ class DependencyManager:
def precache(self):
return string_as_bool(self.get_app_option("precache_dependencies", True))
- def dependency_shell_commands(self, requirements: ToolRequirements, **kwds: Any) -> List[str]:
+ def dependency_shell_commands(self, requirements: ToolRequirements, **kwds: Any) -> list[str]:
requirements_to_dependencies = self.requirements_to_dependencies(requirements, **kwds)
ordered_dependencies = OrderedSet(requirements_to_dependencies.values())
return [
@@ -334,7 +331,7 @@ class DependencyManager:
def uses_tool_shed_dependencies(self):
return any(isinstance(r, ToolShedPackageDependencyResolver) for r in self.dependency_resolvers)
- def find_dep(self, name: str, version: Optional[str] = None, type: str = "package", **kwds):
+ def find_dep(self, name: str, version: str | None = None, type: str = "package", **kwds):
log.debug(f"Find dependency {name} version {version}")
requirements = ToolRequirements([ToolRequirement(name=name, version=version, type=type)])
dep_dict = self._requirements_to_dependencies_dict(requirements, **kwds)
@@ -366,7 +363,7 @@ class DependencyManager:
],
)
- def __parse_resolver_conf_plugins(self, plugin_source: plugin_config.PluginConfigSource) -> List:
+ def __parse_resolver_conf_plugins(self, plugin_source: plugin_config.PluginConfigSource) -> list:
""" """
extra_kwds = dict(dependency_manager=self)
# Use either 'type' from YAML definition or 'resolver_type' from to_dict definition.
@@ -374,7 +371,7 @@ class DependencyManager:
self.resolver_classes, plugin_source, extra_kwds, plugin_type_keys=["type", "resolver_type"]
)
- def __resolvers_dict(self) -> Dict[str, Type]:
+ def __resolvers_dict(self) -> dict[str, type]:
import galaxy.tool_util.deps.resolvers
return plugin_config.plugins_dict(galaxy.tool_util.deps.resolvers, "resolver_type")
@@ -394,7 +391,7 @@ class CachedDependencyManager(DependencyManager):
cached = True
def __init__(
- self, default_base_path: str, conf_file: Optional[str] = None, app_config: Optional[Dict[str, Any]] = None
+ self, default_base_path: str, conf_file: str | None = None, app_config: dict[str, Any] | None = None
) -> None:
super().__init__(default_base_path, conf_file, app_config)
self.tool_dependency_cache_dir = self.get_app_option("tool_dependency_cache_dir") or os.path.join(
diff --git a/lib/galaxy/tool_util/deps/brew_exts.py b/lib/galaxy/tool_util/deps/brew_exts.py
index 2aaaa2af5f5..86a9ef609d1 100755
--- a/lib/galaxy/tool_util/deps/brew_exts.py
+++ b/lib/galaxy/tool_util/deps/brew_exts.py
@@ -29,10 +29,6 @@ import re
import string
import subprocess
import sys
-from typing import (
- List,
- Tuple,
-)
WHITESPACE_PATTERN = re.compile(r"[\s]+")
@@ -49,7 +45,7 @@ CANNOT_DETERMINE_TAP_ERROR_MESSAGE = (
)
VERBOSE = False
RELAXED = False
-BREW_ARGS: List[str] = []
+BREW_ARGS: list[str] = []
class BrewContext:
@@ -492,7 +488,7 @@ def extended_brew_info(recipe):
return extra_info
-def brew_versions_info(package, tap_path: str) -> List[Tuple[str, str, bool]]:
+def brew_versions_info(package, tap_path: str) -> list[tuple[str, str, bool]]:
def versioned(recipe_path: str):
if not os.path.isabs(recipe_path):
recipe_path = os.path.join(os.getcwd(), recipe_path)
@@ -520,8 +516,7 @@ def __action(sys):
def recipe_cellar_path(cellar_path, recipe, version):
recipe_base = recipe.split("/")[-1]
recipe_base_path = os.path.join(cellar_path, recipe_base, version)
- revision_paths = glob.glob(f"{recipe_base_path}_*")
- if revision_paths:
+ if revision_paths := glob.glob(f"{recipe_base_path}_*"):
revisions = (int(x.rsplit("_", 1)[-1]) for x in revision_paths)
max_revision = max(revisions)
recipe_path = f"{recipe_base_path}_{max_revision}"
diff --git a/lib/galaxy/tool_util/deps/conda_util.py b/lib/galaxy/tool_util/deps/conda_util.py
index 90a388e1db2..b301a3d5136 100644
--- a/lib/galaxy/tool_util/deps/conda_util.py
+++ b/lib/galaxy/tool_util/deps/conda_util.py
@@ -8,17 +8,14 @@ import re
import shutil
import sys
import tempfile
-from typing import (
- Any,
+from collections.abc import (
Callable,
- Dict,
Iterable,
Iterator,
- List,
- Optional,
- Tuple,
+)
+from typing import (
+ Any,
TYPE_CHECKING,
- Union,
)
from packaging.version import Version
@@ -83,18 +80,18 @@ def find_conda_prefix() -> str:
class CondaContext(installable.InstallableContext):
installable_description = "Conda"
- _conda_build_available: Optional[bool]
- _conda_version: Optional[Version]
- _libmamba_solver_available: Optional[bool]
+ _conda_build_available: bool | None
+ _conda_version: Version | None
+ _libmamba_solver_available: bool | None
def __init__(
self,
- conda_prefix: Optional[str] = None,
- conda_exec: Optional[Union[str, List[str]]] = None,
- shell_exec: Optional[Callable[..., int]] = None,
+ conda_prefix: str | None = None,
+ conda_exec: str | list[str] | None = None,
+ shell_exec: Callable[..., int] | None = None,
debug: bool = False,
- ensure_channels: Union[str, List[str]] = "",
- condarc_override: Optional[str] = None,
+ ensure_channels: str | list[str] = "",
+ condarc_override: str | None = None,
use_path_exec: bool = USE_PATH_EXEC_DEFAULT,
copy_dependencies: bool = False,
use_local: bool = USE_LOCAL_DEFAULT,
@@ -119,7 +116,7 @@ class CondaContext(installable.InstallableContext):
self.conda_prefix = conda_prefix
if conda_exec is None:
self.conda_exec = self._bin("conda")
- self.ensure_channels: List[str] = listify(ensure_channels)
+ self.ensure_channels: list[str] = listify(ensure_channels)
self.use_local = use_local
self._reset_conda_properties()
@@ -155,7 +152,7 @@ class CondaContext(installable.InstallableContext):
pass
@property
- def _override_channels_args(self) -> List[str]:
+ def _override_channels_args(self) -> list[str]:
override_channels_args = []
if self.ensure_channels:
override_channels_args.append("--override-channels")
@@ -164,7 +161,7 @@ class CondaContext(installable.InstallableContext):
return override_channels_args
@property
- def _solver_args(self) -> List[str]:
+ def _solver_args(self) -> list[str]:
if self._libmamba_solver_available is None:
self._libmamba_solver_available = self.conda_version >= Version("4.12.0") and self.is_package_installed(
"conda-libmamba-solver"
@@ -185,7 +182,7 @@ class CondaContext(installable.InstallableContext):
else:
return 0
- def conda_info(self) -> Dict[str, Any]:
+ def conda_info(self) -> dict[str, Any]:
cmd = listify(self.conda_exec) + ["info", "--json"]
info_out = commands.execute(cmd)
info = json.loads(info_out)
@@ -231,7 +228,7 @@ class CondaContext(installable.InstallableContext):
)
return False
- def exec_command(self, operation: str, args: List[str], stdout_path: Optional[str] = None) -> int:
+ def exec_command(self, operation: str, args: list[str], stdout_path: str | None = None) -> int:
"""
Execute the requested command.
@@ -245,8 +242,8 @@ class CondaContext(installable.InstallableContext):
if self.condarc_override:
env["CONDARC"] = self.condarc_override
cmd_string = shlex_join(cmd)
- kwds: Dict[str, Any] = {}
- conda_exec_home: Optional[str] = None
+ kwds: dict[str, Any] = {}
+ conda_exec_home: str | None = None
try:
if stdout_path:
kwds["stdout"] = open(stdout_path, "w")
@@ -265,7 +262,7 @@ class CondaContext(installable.InstallableContext):
if conda_exec_home:
shutil.rmtree(conda_exec_home, ignore_errors=True)
- def is_package_installed(self, pkg_name: str, version: Optional[str] = None) -> bool:
+ def is_package_installed(self, pkg_name: str, version: str | None = None) -> bool:
list_args = ["-f", "--json", pkg_name]
with tempfile.NamedTemporaryFile("r") as temp:
ret = self.exec_command("list", list_args, stdout_path=temp.name)
@@ -279,7 +276,7 @@ class CondaContext(installable.InstallableContext):
return True
return any(match["version"] == version for match in out)
- def exec_create(self, args: Iterable[str], allow_local: bool = True, stdout_path: Optional[str] = None) -> int:
+ def exec_create(self, args: Iterable[str], allow_local: bool = True, stdout_path: str | None = None) -> int:
"""
Return the process exit code (i.e. 0 in case of success).
"""
@@ -300,7 +297,7 @@ class CondaContext(installable.InstallableContext):
break
return ret
- def exec_remove(self, args: List[str]) -> int:
+ def exec_remove(self, args: list[str]) -> int:
"""
Remove a conda environment using conda env remove -y --name `args`.
@@ -310,7 +307,7 @@ class CondaContext(installable.InstallableContext):
remove_args.extend(args)
return self.exec_command("env remove", remove_args)
- def exec_install(self, args: Iterable[str], allow_local: bool = True, stdout_path: Optional[str] = None) -> int:
+ def exec_install(self, args: Iterable[str], allow_local: bool = True, stdout_path: str | None = None) -> int:
"""
Return the process exit code (i.e. 0 in case of success).
"""
@@ -333,7 +330,7 @@ class CondaContext(installable.InstallableContext):
self._reset_conda_properties()
return ret
- def exec_clean(self, args: Optional[List[str]] = None, quiet: bool = False) -> int:
+ def exec_clean(self, args: list[str] | None = None, quiet: bool = False) -> int:
"""
Clean up after conda installation.
@@ -348,7 +345,7 @@ class CondaContext(installable.InstallableContext):
return self.exec_command("clean", clean_args, stdout_path=stdout_path)
def exec_search(
- self, args: List[str], json: bool = False, offline: bool = False, platform: Optional[str] = None
+ self, args: list[str], json: bool = False, offline: bool = False, platform: str | None = None
) -> str:
"""
Search conda channels for a package
@@ -384,7 +381,7 @@ class CondaContext(installable.InstallableContext):
env_path = self.env_path(env_name)
return os.path.isdir(env_path)
- def get_conda_target_installed_path(self, conda_target: "CondaTarget") -> Optional[str]:
+ def get_conda_target_installed_path(self, conda_target: "CondaTarget") -> str | None:
for env_name in (conda_target.install_environment, conda_target.capitalized_install_environment):
if self.has_env(env_name):
return self.env_path(env_name)
@@ -427,7 +424,7 @@ def installed_conda_targets(conda_context: CondaContext) -> Iterator["CondaTarge
class CondaTarget:
def __init__(
- self, package: str, version: Optional[str] = None, build: Optional[str] = None, channel: Optional[str] = None
+ self, package: str, version: str | None = None, build: str | None = None, channel: str | None = None
) -> None:
if SHELL_UNSAFE_PATTERN.search(package) is not None or not package:
raise ValueError(f"Invalid package [{package}] encountered.")
@@ -549,7 +546,7 @@ def install_conda(conda_context: CondaContext, force_conda_build: bool = False)
def install_conda_targets(
conda_targets: Iterable[CondaTarget],
conda_context: CondaContext,
- env_name: Optional[str] = None,
+ env_name: str | None = None,
allow_local: bool = True,
) -> int:
"""
@@ -595,8 +592,8 @@ def cleanup_failed_install(conda_target: CondaTarget, conda_context: CondaContex
def best_search_result(
- conda_target: CondaTarget, conda_context: CondaContext, offline: bool = False, platform: Optional[str] = None
-) -> Union[Tuple[None, None], Tuple[Dict[str, Any], bool]]:
+ conda_target: CondaTarget, conda_context: CondaContext, offline: bool = False, platform: str | None = None
+) -> tuple[None, None] | tuple[dict[str, Any], bool]:
"""Find best "conda search" result for specified target.
Return (``None``, ``None``) if no results match.
@@ -630,7 +627,7 @@ def best_search_result(
return best_result
-def is_search_hit_exact(conda_target: CondaTarget, search_hit: Dict[str, Any]) -> bool:
+def is_search_hit_exact(conda_target: CondaTarget, search_hit: dict[str, Any]) -> bool:
# It'd be nice to make request verson of 1.0 match available
# version of 1.0.3 or something like that.
target_version = conda_target.version
@@ -646,18 +643,18 @@ def is_conda_target_installed(conda_target: CondaTarget, conda_context: CondaCon
return conda_context.get_conda_target_installed_path(conda_target) is not None
-def filter_installed_targets(conda_targets: Iterable[CondaTarget], conda_context: CondaContext) -> List[CondaTarget]:
+def filter_installed_targets(conda_targets: Iterable[CondaTarget], conda_context: CondaContext) -> list[CondaTarget]:
installed = functools.partial(is_conda_target_installed, conda_context=conda_context)
return list(filter(installed, conda_targets))
def build_isolated_environment(
- conda_packages: Union[CondaTarget, List[CondaTarget]],
+ conda_packages: CondaTarget | list[CondaTarget],
conda_context: CondaContext,
- path: Optional[str] = None,
+ path: str | None = None,
copy: bool = False,
quiet: bool = False,
-) -> Tuple[str, int]:
+) -> tuple[str, int]:
"""Build a new environment (or reuse an existing one from hashes)
for specified conda packages.
"""
@@ -715,7 +712,7 @@ def build_isolated_environment(
shutil.rmtree(tempdir)
-def split_version_build(version: Optional[str]) -> Tuple[Optional[str], Optional[str]]:
+def split_version_build(version: str | None) -> tuple[str | None, str | None]:
"""Split version string into version and build.
Handles '=' separator (conda format) and '--' separator (mulled format).
@@ -730,7 +727,7 @@ def split_version_build(version: Optional[str]) -> Tuple[Optional[str], Optional
return version, build
-def requirement_to_conda_targets(requirement: "ToolRequirement") -> Optional[CondaTarget]:
+def requirement_to_conda_targets(requirement: "ToolRequirement") -> CondaTarget | None:
conda_target = None
if requirement.type == "package":
assert requirement.name
@@ -739,7 +736,7 @@ def requirement_to_conda_targets(requirement: "ToolRequirement") -> Optional[Con
return conda_target
-def requirements_to_conda_targets(requirements: Iterable["ToolRequirement"]) -> List[CondaTarget]:
+def requirements_to_conda_targets(requirements: Iterable["ToolRequirement"]) -> list[CondaTarget]:
conda_targets = (requirement_to_conda_targets(_) for _ in requirements)
return [c for c in conda_targets if c is not None]
diff --git a/lib/galaxy/tool_util/deps/container_classes.py b/lib/galaxy/tool_util/deps/container_classes.py
index 05b33e6a54a..142aa29183a 100644
--- a/lib/galaxy/tool_util/deps/container_classes.py
+++ b/lib/galaxy/tool_util/deps/container_classes.py
@@ -7,11 +7,7 @@ from abc import (
from logging import getLogger
from typing import (
Any,
- Dict,
- List,
Optional,
- Tuple,
- Type,
TYPE_CHECKING,
)
from uuid import uuid4
@@ -125,10 +121,10 @@ class Container(metaclass=ABCMeta):
container_id: str,
app_info: "AppInfo",
tool_info: "ToolInfo",
- destination_info: Dict[str, Any],
+ destination_info: dict[str, Any],
job_info: Optional["JobInfo"],
container_description: Optional["ContainerDescription"],
- container_name: Optional[str] = None,
+ container_name: str | None = None,
) -> None:
self.container_id = container_id
self.app_info = app_info
@@ -137,7 +133,7 @@ class Container(metaclass=ABCMeta):
self.job_info = job_info
self.container_description = container_description
self.container_name = container_name or uuid4().hex
- self.container_info: Dict[str, Any] = {}
+ self.container_info: dict[str, Any] = {}
def prop(self, name: str, default: Any) -> Any:
destination_name = f"{self.container_type}_{name}"
@@ -180,7 +176,7 @@ class Volume:
self.container_type = container_type
@staticmethod
- def parse_volume_str(rawstr: str) -> Tuple[str, str, str]:
+ def parse_volume_str(rawstr: str) -> tuple[str, str, str]:
"""
>>> Volume.parse_volume_str('A:B:rw')
('A', 'B', 'rw')
@@ -267,7 +263,7 @@ class Volume:
return f"{path}:{self.mode}"
-def preprocess_volumes(volumes_raw_str: str, container_type: str) -> List[str]:
+def preprocess_volumes(volumes_raw_str: str, container_type: str) -> list[str]:
"""Process Galaxy volume specification string to either Docker or Singularity specification.
Galaxy allows the mount try "default_ro" which translates to ro for Docker and
@@ -402,8 +398,7 @@ class HasDockerLikeVolumes:
# Not all tools have a tool_directory - strip this out if supplied by
# job_conf.
- tool_directory_index = volumes_str.find("$tool_directory")
- if tool_directory_index > 0:
+ if (tool_directory_index := volumes_str.find("$tool_directory")) > 0:
end_index = volumes_str.find(",", tool_directory_index)
if end_index < 0:
end_index = len(volumes_str)
@@ -412,7 +407,7 @@ class HasDockerLikeVolumes:
return volumes_str
-def _parse_volumes(volumes_raw: str, container_type: str) -> List[DockerVolume]:
+def _parse_volumes(volumes_raw: str, container_type: str) -> list[DockerVolume]:
"""
>>> volumes_raw = "$galaxy_root:ro,$tool_directory:ro,$job_directory:ro,$working_directory:z,$default_file_path:z"
>>> volumes = _parse_volumes(volumes_raw, "docker")
@@ -428,7 +423,7 @@ class DockerContainer(Container, HasDockerLikeVolumes):
container_type = DOCKER_CONTAINER_TYPE
@property
- def docker_host_props(self) -> Dict[str, Any]:
+ def docker_host_props(self) -> dict[str, Any]:
docker_host_props = dict(
docker_cmd=self.prop("cmd", docker_util.DEFAULT_DOCKER_COMMAND),
sudo=asbool(self.prop("sudo", docker_util.DEFAULT_SUDO)),
@@ -438,10 +433,10 @@ class DockerContainer(Container, HasDockerLikeVolumes):
return docker_host_props
@property
- def connection_configuration(self) -> Dict[str, Any]:
+ def connection_configuration(self) -> dict[str, Any]:
return self.docker_host_props
- def build_pull_command(self) -> List[str]:
+ def build_pull_command(self) -> list[str]:
return docker_util.build_pull_command(self.container_id, **self.docker_host_props)
def containerize_command(self, command: str) -> str:
@@ -507,7 +502,7 @@ _on_exit() {{
{cache_command}
{run_command}"""
- def __cache_from_file_command(self, cached_image_file: str, docker_host_props: Dict[str, Any]) -> str:
+ def __cache_from_file_command(self, cached_image_file: str, docker_host_props: dict[str, Any]) -> str:
images_cmd = docker_util.build_docker_images_command(truncate=False, format="json", **docker_host_props)
load_cmd = docker_util.build_docker_load_command(**docker_host_props)
@@ -515,7 +510,7 @@ _on_exit() {{
cached_image_file=cached_image_file, images_cmd=images_cmd, load_cmd=load_cmd
)
- def __get_cached_image_file(self) -> Optional[str]:
+ def __get_cached_image_file(self) -> str | None:
container_id = self.container_id
cache_directory = os.path.abspath(self.__get_destination_overridable_property("container_image_cache_path"))
cache_path = docker_cache_path(cache_directory, container_id)
@@ -538,7 +533,7 @@ def docker_cache_path(cache_directory: str, container_id: str) -> str:
class SingularityContainer(Container, HasDockerLikeVolumes):
container_type = SINGULARITY_CONTAINER_TYPE
- def get_singularity_target_kwds(self) -> Dict[str, Any]:
+ def get_singularity_target_kwds(self) -> dict[str, Any]:
return dict(
singularity_cmd=self.prop("cmd", singularity_util.DEFAULT_SINGULARITY_COMMAND),
sudo=asbool(self.prop("sudo", singularity_util.DEFAULT_SUDO)),
@@ -546,12 +541,12 @@ class SingularityContainer(Container, HasDockerLikeVolumes):
)
@property
- def connection_configuration(self) -> Dict[str, Any]:
+ def connection_configuration(self) -> dict[str, Any]:
return self.get_singularity_target_kwds()
def build_mulled_singularity_pull_command(
self, cache_directory: str, namespace: str = "biocontainers"
- ) -> List[str]:
+ ) -> list[str]:
return singularity_util.pull_mulled_singularity_command(
docker_image_identifier=self.container_id,
cache_directory=cache_directory,
@@ -559,7 +554,7 @@ class SingularityContainer(Container, HasDockerLikeVolumes):
**self.get_singularity_target_kwds(),
)
- def build_singularity_pull_command(self, cache_path: str) -> List[str]:
+ def build_singularity_pull_command(self, cache_path: str) -> list[str]:
return singularity_util.pull_singularity_command(
image_identifier=self.container_id, cache_path=cache_path, **self.get_singularity_target_kwds()
)
@@ -604,7 +599,7 @@ class SingularityContainer(Container, HasDockerLikeVolumes):
return run_command
-CONTAINER_CLASSES: Dict[str, Type[Container]] = dict(
+CONTAINER_CLASSES: dict[str, type[Container]] = dict(
docker=DockerContainer,
singularity=SingularityContainer,
)
diff --git a/lib/galaxy/tool_util/deps/container_resolvers/__init__.py b/lib/galaxy/tool_util/deps/container_resolvers/__init__.py
index 8a5682a3b39..bf0c6269550 100644
--- a/lib/galaxy/tool_util/deps/container_resolvers/__init__.py
+++ b/lib/galaxy/tool_util/deps/container_resolvers/__init__.py
@@ -4,9 +4,9 @@ from abc import (
ABCMeta,
abstractmethod,
)
+from collections.abc import Container
from typing import (
Any,
- Container,
Optional,
TYPE_CHECKING,
)
diff --git a/lib/galaxy/tool_util/deps/container_resolvers/explicit.py b/lib/galaxy/tool_util/deps/container_resolvers/explicit.py
index c1690e1124e..bf4ed7c106e 100644
--- a/lib/galaxy/tool_util/deps/container_resolvers/explicit.py
+++ b/lib/galaxy/tool_util/deps/container_resolvers/explicit.py
@@ -3,9 +3,8 @@
import copy
import logging
import os
+from collections.abc import Container
from typing import (
- Container,
- Optional,
TYPE_CHECKING,
)
@@ -39,7 +38,7 @@ class ExplicitContainerResolver(ContainerResolver):
def resolve(
self, enabled_container_types: Container[str], tool_info: "ToolInfo", **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
"""Find a container explicitly mentioned in tool description.
This ignores the tool requirements and assumes the tool author crafted
@@ -59,7 +58,7 @@ class ExplicitSingularityContainerResolver(ExplicitContainerResolver):
def resolve(
self, enabled_container_types: Container[str], tool_info: "ToolInfo", **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
"""Find a container explicitly mentioned in tool description.
This ignores the tool requirements and assumes the tool author crafted
@@ -99,7 +98,7 @@ class CachedExplicitSingularityContainerResolver(CliContainerResolver):
def resolve(
self, enabled_container_types: Container[str], tool_info: "ToolInfo", install: bool = False, **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
"""Find a container explicitly mentioned in tool description.
This ignores the tool requirements and assumes the tool author crafted
@@ -211,7 +210,7 @@ class FallbackContainerResolver(BaseAdminConfiguredContainerResolver):
def resolve(
self, enabled_container_types: Container[str], tool_info: "ToolInfo", **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
container_description = self._container_description(self.identifier, self.container_type)
if self._match(enabled_container_types, tool_info, container_description):
return container_description
@@ -272,7 +271,7 @@ class MappingContainerResolver(BaseAdminConfiguredContainerResolver):
def resolve(
self, enabled_container_types: Container[str], tool_info: "ToolInfo", **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
tool_id = tool_info.tool_id
# If resolving against dependencies and not a specific tool, skip over this resolver
if not tool_id:
diff --git a/lib/galaxy/tool_util/deps/container_resolvers/mulled.py b/lib/galaxy/tool_util/deps/container_resolvers/mulled.py
index d907abd8851..3626b484296 100644
--- a/lib/galaxy/tool_util/deps/container_resolvers/mulled.py
+++ b/lib/galaxy/tool_util/deps/container_resolvers/mulled.py
@@ -8,21 +8,18 @@ from abc import (
ABCMeta,
abstractmethod,
)
-from typing import (
- Any,
+from collections.abc import (
Callable,
Container as TypingContainer,
- Dict,
- List,
+)
+from typing import (
+ Any,
+ Literal,
NamedTuple,
- Optional,
- Type,
TYPE_CHECKING,
- Union,
)
from requests import Session
-from typing_extensions import Literal
from galaxy.util import (
safe_makedirs,
@@ -74,21 +71,21 @@ log = logging.getLogger(__name__)
class CachedMulledImageSingleTarget(NamedTuple):
package_name: str
- version: Optional[str]
- build: Optional[str]
+ version: str | None
+ build: str | None
image_identifier: str
class CachedV1MulledImageMultiTarget(NamedTuple):
hash: str
- build: Optional[str]
+ build: str | None
image_identifier: str
class CachedV2MulledImageMultiTarget(NamedTuple):
image_name: str
- version_hash: Optional[str]
- build: Optional[str]
+ version_hash: str | None
+ build: str | None
image_identifier: str
@property
@@ -102,7 +99,7 @@ class CachedV2MulledImageMultiTarget(NamedTuple):
return image_name.rsplit("/")[-1]
-CachedTarget = Union[CachedMulledImageSingleTarget, CachedV1MulledImageMultiTarget, CachedV2MulledImageMultiTarget]
+CachedTarget = CachedMulledImageSingleTarget | CachedV1MulledImageMultiTarget | CachedV2MulledImageMultiTarget
class CacheDirectory(metaclass=ABCMeta):
@@ -112,14 +109,14 @@ class CacheDirectory(metaclass=ABCMeta):
self.path = path
self.hash_func = hash_func
- def _list_cached_mulled_images_from_path(self) -> List[CachedTarget]:
+ def _list_cached_mulled_images_from_path(self) -> list[CachedTarget]:
contents = os.listdir(self.path)
sorted_images = version_sorted(contents)
raw_images = (identifier_to_cached_target(name, self.hash_func) for name in sorted_images)
return [i for i in raw_images if i is not None]
@abstractmethod
- def list_cached_mulled_images_from_path(self) -> List[CachedTarget]:
+ def list_cached_mulled_images_from_path(self) -> list[CachedTarget]:
"""Generate a list of cached, mulled images in the cache."""
@abstractmethod
@@ -132,7 +129,7 @@ class UncachedCacheDirectory(CacheDirectory):
def list_cached_mulled_images_from_path(
self,
- ) -> List[CachedTarget]:
+ ) -> list[CachedTarget]:
return self._list_cached_mulled_images_from_path()
def invalidate_cache(self) -> None:
@@ -156,7 +153,7 @@ class DirMtimeCacheDirectory(CacheDirectory):
def list_cached_mulled_images_from_path(
self,
- ) -> List[CachedTarget]:
+ ) -> list[CachedTarget]:
mtime = self.__get_mtime()
if mtime != self.__mtime:
if mtime < self.__mtime:
@@ -172,9 +169,9 @@ class DirMtimeCacheDirectory(CacheDirectory):
self.__contents = []
-def get_cache_directory_cacher(cacher_type: Optional[str]) -> Type[CacheDirectory]:
+def get_cache_directory_cacher(cacher_type: str | None) -> type[CacheDirectory]:
# these can become a separate module and use plugin_config if we need more
- cachers: Dict[str, Type[CacheDirectory]] = {
+ cachers: dict[str, type[CacheDirectory]] = {
UncachedCacheDirectory.cacher_type: UncachedCacheDirectory,
DirMtimeCacheDirectory.cacher_type: DirMtimeCacheDirectory,
}
@@ -183,10 +180,10 @@ def get_cache_directory_cacher(cacher_type: Optional[str]) -> Type[CacheDirector
def list_docker_cached_mulled_images(
- namespace: Optional[str] = None,
+ namespace: str | None = None,
hash_func: Literal["v1", "v2"] = "v2",
- resolution_cache: Optional[ResolutionCache] = None,
-) -> List[CachedTarget]:
+ resolution_cache: ResolutionCache | None = None,
+) -> list[CachedTarget]:
cache_key = "galaxy.tool_util.deps.container_resolvers.mulled:cached_images"
if resolution_cache is not None and cache_key in resolution_cache:
images_and_versions = resolution_cache.get(cache_key)
@@ -215,7 +212,7 @@ def list_docker_cached_mulled_images(
if resolution_cache is not None:
resolution_cache[cache_key] = images_and_versions
- def output_line_to_image(line: str) -> Optional[CachedTarget]:
+ def output_line_to_image(line: str) -> CachedTarget | None:
image = identifier_to_cached_target(line, hash_func, namespace=namespace)
return image
@@ -226,8 +223,8 @@ def list_docker_cached_mulled_images(
def identifier_to_cached_target(
- identifier: str, hash_func: Literal["v1", "v2"], namespace: Optional[str] = None
-) -> Optional[CachedTarget]:
+ identifier: str, hash_func: Literal["v1", "v2"], namespace: str | None = None
+) -> CachedTarget | None:
if ":" in identifier:
image_name, version = identifier.rsplit(":", 1)
else:
@@ -237,7 +234,7 @@ def identifier_to_cached_target(
if not version or version == "latest":
version = None
- image: Optional[CachedTarget] = None
+ image: CachedTarget | None = None
prefix = ""
if namespace is not None:
prefix = f"quay.io/{namespace}/"
@@ -275,18 +272,18 @@ def identifier_to_cached_target(
return image
-def get_filter(namespace: Optional[str]) -> Callable[[str], bool]:
+def get_filter(namespace: str | None) -> Callable[[str], bool]:
prefix = "quay.io/" if namespace is None else f"quay.io/{namespace}"
return lambda name: name.startswith(prefix) and name.count("/") == 2
def find_best_matching_cached_image(
- targets: List[CondaTarget], cached_images: List[CachedTarget], hash_func: Literal["v1", "v2"]
-) -> Optional[CachedTarget]:
+ targets: list[CondaTarget], cached_images: list[CachedTarget], hash_func: Literal["v1", "v2"]
+) -> CachedTarget | None:
if len(targets) == 0:
return None
- image: Optional[CachedTarget] = None
+ image: CachedTarget | None = None
cached_image: CachedTarget
if len(targets) == 1:
target = targets[0]
@@ -333,20 +330,19 @@ def find_best_matching_cached_image(
def docker_cached_container_description(
- targets: List[CondaTarget],
+ targets: list[CondaTarget],
namespace: str,
hash_func: Literal["v1", "v2"] = "v2",
shell: str = DEFAULT_CONTAINER_SHELL,
- resolution_cache: Optional[ResolutionCache] = None,
-) -> Optional[ContainerDescription]:
+ resolution_cache: ResolutionCache | None = None,
+) -> ContainerDescription | None:
if len(targets) == 0:
return None
cached_images = list_docker_cached_mulled_images(namespace, hash_func=hash_func, resolution_cache=resolution_cache)
- image = find_best_matching_cached_image(targets, cached_images, hash_func)
container = None
- if image:
+ if image := find_best_matching_cached_image(targets, cached_images, hash_func):
container = ContainerDescription(
image.image_identifier,
type="docker",
@@ -357,11 +353,11 @@ def docker_cached_container_description(
def singularity_cached_container_description(
- targets: List[CondaTarget],
+ targets: list[CondaTarget],
cache_directory: CacheDirectory,
hash_func: Literal["v1", "v2"] = "v2",
shell: str = DEFAULT_CONTAINER_SHELL,
-) -> Optional[ContainerDescription]:
+) -> ContainerDescription | None:
if len(targets) == 0:
return None
@@ -369,10 +365,9 @@ def singularity_cached_container_description(
return None
cached_images = cache_directory.list_cached_mulled_images_from_path()
- image = find_best_matching_cached_image(targets, cached_images, hash_func)
container = None
- if image:
+ if image := find_best_matching_cached_image(targets, cached_images, hash_func):
container = ContainerDescription(
os.path.abspath(os.path.join(cache_directory.path, image.image_identifier)),
type="singularity",
@@ -382,12 +377,12 @@ def singularity_cached_container_description(
def targets_to_mulled_name(
- targets: List[CondaTarget],
+ targets: list[CondaTarget],
hash_func: Literal["v1", "v2"],
namespace: str,
- resolution_cache: Optional[ResolutionCache] = None,
- session: Optional[Session] = None,
-) -> Optional[str]:
+ resolution_cache: ResolutionCache | None = None,
+ session: Session | None = None,
+) -> str | None:
unresolved_cache_key = "galaxy.tool_util.deps.container_resolvers.mulled:unresolved"
if resolution_cache is not None:
if unresolved_cache_key not in resolution_cache:
@@ -402,7 +397,7 @@ def targets_to_mulled_name(
name = None
- def cached_name(cache_key: str) -> Optional[str]:
+ def cached_name(cache_key: str) -> str | None:
if mulled_resolution_cache:
try:
return resolution_cache.get(cache_key) # type: ignore[union-attr] # mulled_resolution_cache not None implies resolution_cache not None
@@ -531,7 +526,7 @@ class CachedMulledDockerContainerResolver(CliContainerResolver):
def resolve(
self, enabled_container_types: TypingContainer[str], tool_info: "ToolInfo", **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
if (
not self.cli_available
or tool_info.requires_galaxy_python_environment
@@ -556,7 +551,7 @@ class CachedMulledSingularityContainerResolver(SingularityCliContainerResolver):
def resolve(
self, enabled_container_types: TypingContainer[str], tool_info: "ToolInfo", **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
if tool_info.requires_galaxy_python_environment or self.container_type not in enabled_container_types:
return None
@@ -575,7 +570,7 @@ class MulledDockerContainerResolver(CliContainerResolver):
resolver_type = "mulled"
shell = "/bin/bash"
- protocol: Optional[str] = None
+ protocol: str | None = None
def __init__(
self,
@@ -592,11 +587,11 @@ class MulledDockerContainerResolver(CliContainerResolver):
def cached_container_description(
self,
- targets: List[CondaTarget],
+ targets: list[CondaTarget],
namespace: str,
hash_func: Literal["v1", "v2"],
- resolution_cache: Optional[ResolutionCache] = None,
- ) -> Optional[ContainerDescription]:
+ resolution_cache: ResolutionCache | None = None,
+ ) -> ContainerDescription | None:
try:
return docker_cached_container_description(
targets, namespace, hash_func=hash_func, resolution_cache=resolution_cache
@@ -622,9 +617,9 @@ class MulledDockerContainerResolver(CliContainerResolver):
enabled_container_types: TypingContainer[str],
tool_info: "ToolInfo",
install: bool = False,
- session: Optional[Session] = None,
+ session: Session | None = None,
**kwds,
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
resolution_cache = kwds.get("resolution_cache")
if tool_info.requires_galaxy_python_environment or self.container_type not in enabled_container_types:
return None
@@ -705,11 +700,11 @@ class MulledSingularityContainerResolver(SingularityCliContainerResolver, Mulled
def cached_container_description(
self,
- targets: List[CondaTarget],
+ targets: list[CondaTarget],
namespace: str,
hash_func: Literal["v1", "v2"],
- resolution_cache: Optional[ResolutionCache] = None,
- ) -> Optional[ContainerDescription]:
+ resolution_cache: ResolutionCache | None = None,
+ ) -> ContainerDescription | None:
return singularity_cached_container_description(
targets, cache_directory=self.cache_directory, hash_func=hash_func
)
@@ -752,7 +747,7 @@ class BuildMulledDockerContainerResolver(CliContainerResolver):
self.namespace = namespace
self.hash_func = hash_func
self.auto_install = string_as_bool(auto_install)
- self._mulled_kwds: Dict[str, Any] = {
+ self._mulled_kwds: dict[str, Any] = {
"namespace": namespace,
"hash_func": self.hash_func,
"command": "build-and-test",
@@ -767,7 +762,7 @@ class BuildMulledDockerContainerResolver(CliContainerResolver):
def resolve(
self, enabled_container_types: TypingContainer[str], tool_info: "ToolInfo", install: bool = False, **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
if tool_info.requires_galaxy_python_environment or self.container_type not in enabled_container_types:
return None
@@ -815,7 +810,7 @@ class BuildMulledSingularityContainerResolver(SingularityCliContainerResolver):
def resolve(
self, enabled_container_types: TypingContainer[str], tool_info: "ToolInfo", install: bool = False, **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
if tool_info.requires_galaxy_python_environment or self.container_type not in enabled_container_types:
return None
@@ -834,11 +829,11 @@ class BuildMulledSingularityContainerResolver(SingularityCliContainerResolver):
return f"BuildSingularityContainerResolver[cache_directory={self.cache_directory.path}]"
-def mulled_targets(tool_info: "ToolInfo") -> List[CondaTarget]:
+def mulled_targets(tool_info: "ToolInfo") -> list[CondaTarget]:
return requirements_to_mulled_targets(tool_info.requirements)
-def image_name(targets: List[CondaTarget], hash_func: Literal["v1", "v2"]) -> str:
+def image_name(targets: list[CondaTarget], hash_func: Literal["v1", "v2"]) -> str:
if len(targets) == 0:
return "no targets"
elif hash_func == "v2":
diff --git a/lib/galaxy/tool_util/deps/container_resolvers/test.py b/lib/galaxy/tool_util/deps/container_resolvers/test.py
index 7099d9abe1c..80564fc68cc 100644
--- a/lib/galaxy/tool_util/deps/container_resolvers/test.py
+++ b/lib/galaxy/tool_util/deps/container_resolvers/test.py
@@ -1,5 +1,5 @@
+from collections.abc import Container
from typing import (
- Container,
Optional,
TYPE_CHECKING,
)
diff --git a/lib/galaxy/tool_util/deps/container_volumes.py b/lib/galaxy/tool_util/deps/container_volumes.py
index 01747bba15b..47764a879fb 100644
--- a/lib/galaxy/tool_util/deps/container_volumes.py
+++ b/lib/galaxy/tool_util/deps/container_volumes.py
@@ -3,13 +3,12 @@ from abc import (
ABCMeta,
abstractmethod,
)
-from typing import Optional
class ContainerVolume(metaclass=ABCMeta):
valid_modes = frozenset({"ro", "rw", "z", "Z"})
- def __init__(self, path: str, host_path: Optional[str] = None, mode: Optional[str] = None):
+ def __init__(self, path: str, host_path: str | None = None, mode: str | None = None):
self.path = path
self.host_path = host_path
self.mode = mode
diff --git a/lib/galaxy/tool_util/deps/containers.py b/lib/galaxy/tool_util/deps/containers.py
index 9fd84d49109..5a3a4f31f27 100644
--- a/lib/galaxy/tool_util/deps/containers.py
+++ b/lib/galaxy/tool_util/deps/containers.py
@@ -1,18 +1,15 @@
import collections
import logging
import os
+from collections.abc import Container as TypingContainer
from typing import (
Any,
- Container as TypingContainer,
- Dict,
- List,
+ Literal,
Optional,
- Type,
TYPE_CHECKING,
)
from requests import Session
-from typing_extensions import Literal
from galaxy.util import (
asbool,
@@ -67,14 +64,14 @@ class ContainerFinder:
self.app_info = app_info
self.mulled_resolution_cache = mulled_resolution_cache
self.default_container_registry = ContainerRegistry(app_info, mulled_resolution_cache=mulled_resolution_cache)
- self.destination_container_registeries: Dict[str, ContainerRegistry] = {}
+ self.destination_container_registeries: dict[str, ContainerRegistry] = {}
- def _enabled_container_types(self, destination_info: Dict[str, Any]) -> List[str]:
+ def _enabled_container_types(self, destination_info: dict[str, Any]) -> list[str]:
return [t for t in ALL_CONTAINER_TYPES if self.__container_type_enabled(t, destination_info)]
def find_best_container_description(
self, enabled_container_types: TypingContainer[str], tool_info: "ToolInfo", **kwds
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
"""Regardless of destination properties - find best container for tool.
Given container types and container.ToolInfo description of the tool."""
@@ -84,11 +81,11 @@ class ContainerFinder:
def resolve(
self, enabled_container_types: TypingContainer[str], tool_info: "ToolInfo", **kwds
- ) -> Optional[ResolvedContainerDescription]:
+ ) -> ResolvedContainerDescription | None:
"""Regardless of destination properties - find ResolvedContainerDescription for tool."""
return self.default_container_registry.resolve(enabled_container_types, tool_info, **kwds)
- def _container_registry_for_destination(self, destination_info: Dict[str, Any]) -> "ContainerRegistry":
+ def _container_registry_for_destination(self, destination_info: dict[str, Any]) -> "ContainerRegistry":
destination_id = destination_info.get("id") # Probably not the way to get the ID?
destination_container_registry = None
if destination_id and destination_id not in self.destination_container_registeries:
@@ -116,8 +113,8 @@ class ContainerFinder:
return destination_container_registry or self.default_container_registry
def find_container(
- self, tool_info: "ToolInfo", destination_info: Dict[str, Any], job_info: "JobInfo"
- ) -> Optional[Container]:
+ self, tool_info: "ToolInfo", destination_info: dict[str, Any], job_info: "JobInfo"
+ ) -> Container | None:
enabled_container_types = self._enabled_container_types(destination_info)
# Short-cut everything else and just skip checks if no container type is enabled.
@@ -125,10 +122,10 @@ class ContainerFinder:
return None
def __destination_container(
- container_description: Optional[ContainerDescription] = None,
- container_id: Optional[str] = None,
- container_type: Optional[str] = None,
- ) -> Optional[Container]:
+ container_description: ContainerDescription | None = None,
+ container_id: str | None = None,
+ container_type: str | None = None,
+ ) -> Container | None:
"""
either container_description or container_id and container_type must me given
"""
@@ -150,8 +147,8 @@ class ContainerFinder:
return container
def container_from_description_from_dicts(
- destination_container_dicts: List[Dict[str, Any]],
- ) -> Optional[Container]:
+ destination_container_dicts: list[dict[str, Any]],
+ ) -> Container | None:
for destination_container_dict in destination_container_dicts:
container_description = ContainerDescription.from_dict(destination_container_dict)
if container_description:
@@ -201,7 +198,7 @@ class ContainerFinder:
def resolution_cache(self) -> ResolutionCache:
return self.default_container_registry.get_resolution_cache()
- def __overridden_container_id(self, container_type: str, destination_info: Dict[str, Any]) -> Optional[str]:
+ def __overridden_container_id(self, container_type: str, destination_info: dict[str, Any]) -> str | None:
if not self.__container_type_enabled(container_type, destination_info):
return None
if f"{container_type}_container_id_override" in destination_info:
@@ -211,23 +208,20 @@ class ContainerFinder:
return None
def __build_container_id_from_parts(
- self, container_type: str, destination_info: Dict[str, Any], mode: Literal["default", "override"]
+ self, container_type: str, destination_info: dict[str, Any], mode: Literal["default", "override"]
) -> str:
repo = ""
owner = ""
- repo_key = f"{container_type}_repo_{mode}"
- owner_key = f"{container_type}_owner_{mode}"
- if repo_key in destination_info:
+ if (repo_key := f"{container_type}_repo_{mode}") in destination_info:
repo = f"{destination_info[repo_key]}/"
- if owner_key in destination_info:
+ if (owner_key := f"{container_type}_owner_{mode}") in destination_info:
owner = f"{destination_info[owner_key]}/"
cont_id = repo + owner + destination_info[f"{container_type}_image_{mode}"]
- tag_key = f"{container_type}_tag_{mode}"
- if tag_key in destination_info:
+ if (tag_key := f"{container_type}_tag_{mode}") in destination_info:
cont_id += f":{destination_info[tag_key]}"
return cont_id
- def __default_container_id(self, container_type: str, destination_info: Dict[str, Any]) -> Optional[str]:
+ def __default_container_id(self, container_type: str, destination_info: dict[str, Any]) -> str | None:
if not self.__container_type_enabled(container_type, destination_info):
return None
key = f"{container_type}_default_container_id"
@@ -245,10 +239,10 @@ class ContainerFinder:
container_id: str,
container_type: str,
tool_info: "ToolInfo",
- destination_info: Dict[str, Any],
+ destination_info: dict[str, Any],
job_info: "JobInfo",
- container_description: Optional[ContainerDescription] = None,
- ) -> Optional[Container]:
+ container_description: ContainerDescription | None = None,
+ ) -> Container | None:
# TODO: ensure destination_info is dict-like
if not self.__container_type_enabled(container_type, destination_info):
return None
@@ -261,12 +255,12 @@ class ContainerFinder:
container_id, self.app_info, tool_info, destination_info, job_info, container_description
)
- def __container_type_enabled(self, container_type: str, destination_info: Dict[str, Any]) -> bool:
+ def __container_type_enabled(self, container_type: str, destination_info: dict[str, Any]) -> bool:
return asbool(destination_info.get(f"{container_type}_enabled", False))
class NullContainerFinder:
- def find_container(self, tool_info: "ToolInfo", destination_info: Dict[str, Any], job_info: "JobInfo") -> None:
+ def find_container(self, tool_info: "ToolInfo", destination_info: dict[str, Any], job_info: "JobInfo") -> None:
return None
@@ -276,7 +270,7 @@ class ContainerRegistry:
def __init__(
self,
app_info: "AppInfo",
- destination_info: Optional[Dict[str, Any]] = None,
+ destination_info: dict[str, Any] | None = None,
mulled_resolution_cache: Optional["Cache"] = None,
) -> None:
self.resolver_classes = self.__resolvers_dict()
@@ -286,8 +280,8 @@ class ContainerRegistry:
self.mulled_resolution_cache = mulled_resolution_cache
def __build_container_resolvers(
- self, app_info: "AppInfo", destination_info: Optional[Dict[str, Any]]
- ) -> List["ContainerResolver"]:
+ self, app_info: "AppInfo", destination_info: dict[str, Any] | None
+ ) -> list["ContainerResolver"]:
app_conf_file = getattr(app_info, "container_resolvers_config_file", None)
app_conf_dict = getattr(app_info, "container_resolvers_config_dict", None)
@@ -313,12 +307,12 @@ class ContainerRegistry:
return self._parse_resolver_conf(plugin_source)
return self.__default_container_resolvers()
- def _parse_resolver_conf(self, plugin_source: "PluginConfigSource") -> List["ContainerResolver"]:
+ def _parse_resolver_conf(self, plugin_source: "PluginConfigSource") -> list["ContainerResolver"]:
extra_kwds = {"app_info": self.app_info}
return plugin_config.load_plugins(self.resolver_classes, plugin_source, extra_kwds)
- def __default_container_resolvers(self) -> List["ContainerResolver"]:
- default_resolvers: List[ContainerResolver] = [
+ def __default_container_resolvers(self) -> list["ContainerResolver"]:
+ default_resolvers: list[ContainerResolver] = [
ExplicitContainerResolver(self.app_info),
ExplicitSingularityContainerResolver(self.app_info),
]
@@ -345,7 +339,7 @@ class ContainerRegistry:
)
return default_resolvers
- def __resolvers_dict(self) -> Dict[str, Type["ContainerResolver"]]:
+ def __resolvers_dict(self) -> dict[str, type["ContainerResolver"]]:
return plugin_config.plugins_dict(container_resolvers, "resolver_type")
def get_resolution_cache(self) -> ResolutionCache:
@@ -356,7 +350,7 @@ class ContainerRegistry:
def find_best_container_description(
self, enabled_container_types: TypingContainer[str], tool_info: "ToolInfo", **kwds: Any
- ) -> Optional[ContainerDescription]:
+ ) -> ContainerDescription | None:
"""Yield best container description of supplied types matching tool info."""
try:
resolved_container_description = self.resolve(enabled_container_types, tool_info, **kwds)
@@ -369,12 +363,12 @@ class ContainerRegistry:
self,
enabled_container_types: TypingContainer[str],
tool_info: "ToolInfo",
- index: Optional[int] = None,
- resolver_type: Optional[str] = None,
+ index: int | None = None,
+ resolver_type: str | None = None,
install: bool = True,
- resolution_cache: Optional[ResolutionCache] = None,
- session: Optional[Session] = None,
- ) -> Optional[ResolvedContainerDescription]:
+ resolution_cache: ResolutionCache | None = None,
+ session: Session | None = None,
+ ) -> ResolvedContainerDescription | None:
resolution_cache = resolution_cache or self.get_resolution_cache()
for i, container_resolver in enumerate(self.container_resolvers):
if index is not None and i != index:
diff --git a/lib/galaxy/tool_util/deps/dependencies.py b/lib/galaxy/tool_util/deps/dependencies.py
index 6078ee76c1a..71f8619fcac 100644
--- a/lib/galaxy/tool_util/deps/dependencies.py
+++ b/lib/galaxy/tool_util/deps/dependencies.py
@@ -1,7 +1,5 @@
from typing import (
Any,
- List,
- Optional,
Union,
)
@@ -17,20 +15,20 @@ from .mulled.util import DEFAULT_CHANNELS
class AppInfo:
def __init__(
self,
- galaxy_root_dir: Optional[str] = None,
- default_file_path: Optional[str] = None,
- tool_data_path: Optional[str] = None,
- galaxy_data_manager_data_path: Optional[str] = None,
- shed_tool_data_path: Optional[str] = None,
+ galaxy_root_dir: str | None = None,
+ default_file_path: str | None = None,
+ tool_data_path: str | None = None,
+ galaxy_data_manager_data_path: str | None = None,
+ shed_tool_data_path: str | None = None,
outputs_to_working_directory: bool = False,
- container_image_cache_path: Optional[str] = None,
- library_import_dir: Optional[str] = None,
+ container_image_cache_path: str | None = None,
+ library_import_dir: str | None = None,
enable_mulled_containers: bool = False,
- container_resolvers_config_file: Optional[str] = None,
- container_resolvers_config_dict: Optional[List[Any]] = None,
- involucro_path: Optional[str] = None,
+ container_resolvers_config_file: str | None = None,
+ container_resolvers_config_dict: list[Any] | None = None,
+ involucro_path: str | None = None,
involucro_auto_init: bool = True,
- mulled_channels: List[str] = DEFAULT_CHANNELS,
+ mulled_channels: list[str] = DEFAULT_CHANNELS,
) -> None:
self.galaxy_root_dir = galaxy_root_dir
self.default_file_path = default_file_path
@@ -56,13 +54,13 @@ class ToolInfo:
def __init__(
self,
- container_descriptions: Optional[List["ContainerDescription"]] = None,
- requirements: Optional[Union["ToolRequirements", List["ToolRequirement"]]] = None,
+ container_descriptions: list["ContainerDescription"] | None = None,
+ requirements: Union["ToolRequirements", list["ToolRequirement"]] | None = None,
requires_galaxy_python_environment: bool = False,
env_pass_through=None,
guest_ports=None,
- tool_id: Optional[str] = None,
- tool_version: Optional[str] = None,
+ tool_id: str | None = None,
+ tool_version: str | None = None,
profile: float = -1,
):
if env_pass_through is None:
diff --git a/lib/galaxy/tool_util/deps/docker_util.py b/lib/galaxy/tool_util/deps/docker_util.py
index fdf75a70fb4..ec6753340bc 100644
--- a/lib/galaxy/tool_util/deps/docker_util.py
+++ b/lib/galaxy/tool_util/deps/docker_util.py
@@ -7,10 +7,7 @@ import os
import shlex
import sys
from typing import (
- List,
- Optional,
TYPE_CHECKING,
- Union,
)
if TYPE_CHECKING:
@@ -32,26 +29,26 @@ DEFAULT_SET_USER = None if sys.platform == "darwin" else "$UID"
DEFAULT_RUN_EXTRA_ARGUMENTS = None
-def kill_command(container: str, signal: Optional[str] = None, **kwds) -> List[str]:
+def kill_command(container: str, signal: str | None = None, **kwds) -> list[str]:
args = (["-s", signal] if signal else []) + [container]
return command_list("kill", args, **kwds)
-def logs_command(container: str, **kwds) -> List[str]:
+def logs_command(container: str, **kwds) -> list[str]:
return command_list("logs", [container], **kwds)
-def build_command(image: str, docker_build_path: str, **kwds) -> List[str]:
+def build_command(image: str, docker_build_path: str, **kwds) -> list[str]:
if os.path.isfile(docker_build_path):
docker_build_path = os.path.dirname(os.path.abspath(docker_build_path))
return command_list("build", ["-t", image, docker_build_path], **kwds)
-def build_save_image_command(image: str, destination: str, **kwds) -> List[str]:
+def build_save_image_command(image: str, destination: str, **kwds) -> list[str]:
return command_list("save", ["-o", destination, image], **kwds)
-def build_pull_command(tag: str, **kwds) -> List[str]:
+def build_pull_command(tag: str, **kwds) -> list[str]:
return command_list("pull", [tag], **kwds)
@@ -63,7 +60,7 @@ def build_docker_cache_command(image: str, **kwds) -> str:
return cache_command
-def build_docker_images_command(truncate=True, format: Optional[str] = None, **kwds) -> Union[str, List[str]]:
+def build_docker_images_command(truncate=True, format: str | None = None, **kwds) -> str | list[str]:
args = []
if not truncate:
args.append("--no-trunc")
@@ -72,7 +69,7 @@ def build_docker_images_command(truncate=True, format: Optional[str] = None, **k
return command_shell("images", args, **kwds)
-def build_docker_load_command(**kwds) -> Union[str, List[str]]:
+def build_docker_load_command(**kwds) -> str | list[str]:
return command_shell("load", [])
@@ -81,7 +78,7 @@ def build_docker_simple_command(
docker_cmd: str = DEFAULT_DOCKER_COMMAND,
sudo: bool = DEFAULT_SUDO,
sudo_cmd: str = DEFAULT_SUDO_COMMAND,
- container_name: Optional[str] = None,
+ container_name: str | None = None,
**kwd,
) -> str:
command_parts = _docker_prefix(
@@ -99,24 +96,24 @@ def build_docker_run_command(
image: str,
interactive: bool = False,
terminal: bool = False,
- tag: Optional[str] = None,
- volumes: Optional[List["DockerVolume"]] = None,
- volumes_from: Optional[str] = DEFAULT_VOLUMES_FROM,
- memory: Optional[str] = DEFAULT_MEMORY,
- env_directives: Optional[List[str]] = None,
- working_directory: Optional[str] = DEFAULT_WORKING_DIRECTORY,
- name: Optional[str] = None,
- net: Optional[str] = DEFAULT_NET,
- run_extra_arguments: Optional[str] = DEFAULT_RUN_EXTRA_ARGUMENTS,
+ tag: str | None = None,
+ volumes: list["DockerVolume"] | None = None,
+ volumes_from: str | None = DEFAULT_VOLUMES_FROM,
+ memory: str | None = DEFAULT_MEMORY,
+ env_directives: list[str] | None = None,
+ working_directory: str | None = DEFAULT_WORKING_DIRECTORY,
+ name: str | None = None,
+ net: str | None = DEFAULT_NET,
+ run_extra_arguments: str | None = DEFAULT_RUN_EXTRA_ARGUMENTS,
docker_cmd: str = DEFAULT_DOCKER_COMMAND,
sudo: bool = DEFAULT_SUDO,
sudo_cmd: str = DEFAULT_SUDO_COMMAND,
auto_rm: bool = DEFAULT_AUTO_REMOVE,
- set_user: Optional[str] = DEFAULT_SET_USER,
- host: Optional[str] = DEFAULT_HOST,
- guest_ports: Union[bool, str, List[str]] = False,
- host_port_cmd: Optional[str] = None,
- container_name: Optional[str] = None,
+ set_user: str | None = DEFAULT_SET_USER,
+ host: str | None = DEFAULT_HOST,
+ guest_ports: bool | str | list[str] = False,
+ host_port_cmd: str | None = None,
+ container_name: str | None = None,
) -> str:
env_directives = env_directives or []
volumes = volumes or []
@@ -179,7 +176,7 @@ def build_docker_run_command(
return " ".join(command_parts)
-def command_list(command: str, command_args: Optional[List[str]] = None, **kwds) -> List[str]:
+def command_list(command: str, command_args: list[str] | None = None, **kwds) -> list[str]:
"""Return Docker command as an argv list."""
command_args = command_args or []
command_parts = _docker_prefix(**kwds)
@@ -188,7 +185,7 @@ def command_list(command: str, command_args: Optional[List[str]] = None, **kwds)
return command_parts
-def command_shell(command: str, command_args: Optional[List[str]] = None, **kwds) -> Union[str, List[str]]:
+def command_shell(command: str, command_args: list[str] | None = None, **kwds) -> str | list[str]:
"""Return Docker command as a string for a shell or command-list."""
command_args = command_args or []
cmd = command_list(command, command_args, **kwds)
@@ -203,9 +200,9 @@ def _docker_prefix(
docker_cmd: str = DEFAULT_DOCKER_COMMAND,
sudo: bool = DEFAULT_SUDO,
sudo_cmd: str = DEFAULT_SUDO_COMMAND,
- host: Optional[str] = DEFAULT_HOST,
+ host: str | None = DEFAULT_HOST,
**kwds,
-) -> List[str]:
+) -> list[str]:
"""Prefix to issue a docker command."""
command_parts = []
if sudo:
diff --git a/lib/galaxy/tool_util/deps/dockerfiles.py b/lib/galaxy/tool_util/deps/dockerfiles.py
index 2ca95f375ba..510a41a0dcf 100644
--- a/lib/galaxy/tool_util/deps/dockerfiles.py
+++ b/lib/galaxy/tool_util/deps/dockerfiles.py
@@ -46,8 +46,7 @@ def dockerfile_build(path, dockerfile=None, error=log.error, **kwds):
commands.execute(docker_command_parts)
commands.execute(docker_command_parts)
- docker_image_cache = kwds["docker_image_cache"]
- if docker_image_cache:
+ if docker_image_cache := kwds["docker_image_cache"]:
destination = docker_cache_path(docker_image_cache, image_identifier)
save_image_command_parts = docker_util.build_save_image_command(
image_identifier, destination, **docker_host_args(**kwds)
diff --git a/lib/galaxy/tool_util/deps/mulled/get_tests.py b/lib/galaxy/tool_util/deps/mulled/get_tests.py
index 0c1ad27cbbb..061ad1da301 100644
--- a/lib/galaxy/tool_util/deps/mulled/get_tests.py
+++ b/lib/galaxy/tool_util/deps/mulled/get_tests.py
@@ -12,9 +12,6 @@ import os.path
from pathlib import Path
from typing import (
Any,
- Dict,
- List,
- Optional,
)
import yaml
@@ -50,7 +47,7 @@ INSTALL_JINJA_EXCEPTION = (
)
-def get_commands_from_yaml(yaml_content: bytes) -> Optional[Dict[str, Any]]:
+def get_commands_from_yaml(yaml_content: bytes) -> dict[str, Any] | None:
"""
Parse tests from Conda's meta.yaml file contents
"""
@@ -94,7 +91,7 @@ def get_commands_from_yaml(yaml_content: bytes) -> Optional[Dict[str, Any]]:
return package_tests
-def get_run_test(file: str) -> Dict[str, Any]:
+def get_run_test(file: str) -> dict[str, Any]:
r"""
Get tests from a run_test.sh file
"""
@@ -103,9 +100,7 @@ def get_run_test(file: str) -> Dict[str, Any]:
return package_tests
-def get_anaconda_url(
- container: str, anaconda_channel: str = "bioconda", conda_platform_str: Optional[str] = None
-) -> str:
+def get_anaconda_url(container: str, anaconda_channel: str = "bioconda", conda_platform_str: str | None = None) -> str:
"""
Download tarball from anaconda for test
"""
@@ -115,7 +110,7 @@ def get_anaconda_url(
return f"https://anaconda.org/{anaconda_channel}/{name[0]}/{name[1]}/download/{conda_platform_str}/{'-'.join(name)}.tar.bz2"
-def get_test_from_anaconda(url: str) -> Optional[Dict[str, Any]]:
+def get_test_from_anaconda(url: str) -> dict[str, Any] | None:
"""
Given the URL of an anaconda tarball, return tests
"""
@@ -135,10 +130,10 @@ def get_test_from_anaconda(url: str) -> Optional[Dict[str, Any]]:
def find_anaconda_download_url(
name: str,
version: str,
- build: Optional[str] = None,
+ build: str | None = None,
anaconda_channel: str = "bioconda",
- conda_platform_str: Optional[str] = None,
-) -> Optional[str]:
+ conda_platform_str: str | None = None,
+) -> str | None:
"""
Find the anaconda download url for a given package.
"""
@@ -219,11 +214,11 @@ def try_a_func(func1, func2, param, container):
def deep_test_search(
container: str,
- recipes_path: Optional[str] = None,
+ recipes_path: str | None = None,
anaconda_channel: str = "bioconda",
github_repo: str = "bioconda/bioconda-recipes",
- conda_platform_str: Optional[str] = None,
-) -> Dict[str, Any]:
+ conda_platform_str: str | None = None,
+) -> dict[str, Any]:
"""
Look in bioconda-recipes repo as well as anaconda for the tests, checking in multiple possible locations. If no test is found for the specified version, search if other package versions have a test available.
"""
@@ -287,12 +282,12 @@ def deep_test_search(
def main_test_search(
container: str,
- recipes_path: Optional[str] = None,
+ recipes_path: str | None = None,
deep: bool = False,
anaconda_channel: str = "bioconda",
github_repo: str = "bioconda/bioconda-recipes",
- conda_platform_str: Optional[str] = None,
-) -> Dict[str, Any]:
+ conda_platform_str: str | None = None,
+) -> dict[str, Any]:
"""
Download tarball from anaconda for test
"""
@@ -309,7 +304,7 @@ def main_test_search(
return {"container": container}
-def import_test_to_command_list(import_lang: str, import_: str) -> List[str]:
+def import_test_to_command_list(import_lang: str, import_: str) -> list[str]:
if import_lang == "python -c":
return ["python", "-c", f"import {import_}"]
elif import_lang == "perl -e":
@@ -320,18 +315,18 @@ def import_test_to_command_list(import_lang: str, import_: str) -> List[str]:
def hashed_test_search(
container: str,
- recipes_path: Optional[str] = None,
+ recipes_path: str | None = None,
deep: bool = False,
anaconda_channel: str = "bioconda",
github_repo: str = "bioconda/bioconda-recipes",
- conda_platform_str: Optional[str] = None,
-) -> Dict[str, Any]:
+ conda_platform_str: str | None = None,
+) -> dict[str, Any]:
"""
Get test for hashed containers
"""
if conda_platform_str is None:
conda_platform_str = conda_platform()
- package_tests: Dict[str, Any] = {"commands": [], "imports": [], "container": container, "import_lang": "python -c"}
+ package_tests: dict[str, Any] = {"commands": [], "imports": [], "container": container, "import_lang": "python -c"}
response = requests.get(
f"https://raw.githubusercontent.com/BioContainers/multi-package-containers/master/combinations/{container}.tsv",
diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_build.py b/lib/galaxy/tool_util/deps/mulled/mulled_build.py
index 480b04596bf..28b10365850 100644
--- a/lib/galaxy/tool_util/deps/mulled/mulled_build.py
+++ b/lib/galaxy/tool_util/deps/mulled/mulled_build.py
@@ -18,20 +18,20 @@ import stat
import string
import subprocess
import sys
+from collections.abc import (
+ Callable,
+ Iterable,
+)
from sys import platform as _platform
from typing import (
Any,
- Callable,
- Dict,
- Iterable,
- List,
+ Literal,
NoReturn,
Optional,
TYPE_CHECKING,
)
import yaml
-from typing_extensions import Literal
from galaxy.tool_util.deps import installable
from galaxy.tool_util.deps.conda_util import (
@@ -89,14 +89,14 @@ DockerPlatform = Literal[
"linux/riscv64",
]
-DOCKER_TO_CONDA_PLATFORM: Dict[DockerPlatform, str] = {
+DOCKER_TO_CONDA_PLATFORM: dict[DockerPlatform, str] = {
"linux/amd64": "linux-64",
"linux/arm64": "linux-aarch64",
"linux/arm/v7": "linux-armv7l",
"linux/ppc64le": "linux-ppc64le",
"linux/riscv64": "linux-riscv64",
}
-MACHINE_TO_DOCKER_PLATFORM: Dict[str, DockerPlatform] = {
+MACHINE_TO_DOCKER_PLATFORM: dict[str, DockerPlatform] = {
"x86_64": "linux/amd64",
"amd64": "linux/amd64",
"aarch64": "linux/arm64",
@@ -161,7 +161,7 @@ def get_tests(args, pkg_path):
if tests_imports and "python" in requirements:
tests.append(" && ".join(f'python -c "import {imp}"' for imp in tests_imports))
elif tests_imports and ("perl" in requirements or "perl-threaded" in requirements):
- tests.append(" && ".join(f'''perl -e "use {imp};\"''' for imp in tests_imports))
+ tests.append(" && ".join(f"""perl -e "use {imp};\"""" for imp in tests_imports))
tests = " && ".join(tests)
tests = tests.replace("$R ", "Rscript ")
@@ -224,7 +224,7 @@ def conda_platform() -> str:
return conda_arch_map.get(machine, default_platform)
-def docker_platform_to_conda_subdir(target_docker_platform: Optional[DockerPlatform]) -> str:
+def docker_platform_to_conda_subdir(target_docker_platform: DockerPlatform | None) -> str:
"""Return the conda subdir for an explicit Docker target, or for the host when unset."""
if target_docker_platform is None:
return conda_platform()
@@ -234,7 +234,7 @@ def docker_platform_to_conda_subdir(target_docker_platform: Optional[DockerPlatf
raise ValueError(f"Unsupported target platform '{target_docker_platform}'") from None
-def docker_platform_tag_suffix(target_platform: Optional[DockerPlatform]) -> Optional[str]:
+def docker_platform_tag_suffix(target_platform: DockerPlatform | None) -> str | None:
"""Return an image-tag suffix, preserving unsuffixed tags for legacy amd64 images."""
target_platform = target_platform or MACHINE_TO_DOCKER_PLATFORM.get(
_platform_module.machine().lower(), "linux/amd64"
@@ -244,7 +244,7 @@ def docker_platform_tag_suffix(target_platform: Optional[DockerPlatform]) -> Opt
return target_platform[len("linux/") :].replace("/", "-")
-def apply_platform_tag_suffix(image: str, target_platform: Optional[DockerPlatform]) -> str:
+def apply_platform_tag_suffix(image: str, target_platform: DockerPlatform | None) -> str:
suffix = docker_platform_tag_suffix(target_platform)
if suffix is None:
return image
@@ -258,15 +258,15 @@ def apply_platform_tag_suffix(image: str, target_platform: Optional[DockerPlatfo
def get_conda_hits_for_targets(
- targets: Iterable[CondaTarget], conda_context: CondaContext, conda_platform_str: Optional[str] = None
-) -> List[Dict[str, Any]]:
+ targets: Iterable[CondaTarget], conda_context: CondaContext, conda_platform_str: str | None = None
+) -> list[dict[str, Any]]:
platform = conda_platform_str or conda_platform()
search_results = (best_search_result(t, conda_context, platform=platform)[0] for t in targets)
return [r for r in search_results if r]
def base_image_for_targets(
- targets: Iterable[CondaTarget], conda_context: CondaContext, conda_platform_str: Optional[str] = None
+ targets: Iterable[CondaTarget], conda_context: CondaContext, conda_platform_str: str | None = None
) -> str:
"""
determine base image (DEFAULT_BASE_IMAGE/DEFAULT_EXTENDED_BASE_IMAGE) for a
@@ -304,32 +304,32 @@ class BuildExistsException(Exception):
def mull_targets(
- targets: List[CondaTarget],
+ targets: list[CondaTarget],
involucro_context: Optional["InvolucroContext"] = None,
command: str = "build",
- channels: List[str] = DEFAULT_CHANNELS,
+ channels: list[str] = DEFAULT_CHANNELS,
namespace: str = "biocontainers",
test: str = "true",
- test_files: Optional[List[str]] = None,
- image_build: Optional[str] = None,
- name_override: Optional[str] = None,
+ test_files: list[str] | None = None,
+ image_build: str | None = None,
+ name_override: str | None = None,
repository_template: str = DEFAULT_REPOSITORY_TEMPLATE,
dry_run: bool = False,
- conda_version: Optional[str] = None,
- mamba_version: Optional[str] = None,
+ conda_version: str | None = None,
+ mamba_version: str | None = None,
use_mamba: bool = False,
verbose: bool = False,
- binds: List[str] = DEFAULT_BINDS,
+ binds: list[str] = DEFAULT_BINDS,
rebuild: bool = True,
- oauth_token: Optional[str] = None,
+ oauth_token: str | None = None,
hash_func: Literal["v1", "v2"] = "v2",
singularity: bool = False,
singularity_image_dir: "StrPath" = "singularity_import",
- base_image: Optional[str] = None,
+ base_image: str | None = None,
determine_base_image: bool = True,
invfile: str = INVFILE,
strict_channel_priority: bool = True,
- target_platform: Optional[DockerPlatform] = None,
+ target_platform: DockerPlatform | None = None,
) -> int:
conda_platform_str = docker_platform_to_conda_subdir(target_platform)
if singularity and target_platform:
@@ -421,7 +421,7 @@ def mull_targets(
involucro_args.extend(["-set", f"TEST={test}"])
verbose_opt = "--verbose" if verbose else "--quiet"
- specs: List[str] = []
+ specs: list[str] = []
if conda_version is not None:
specs.append(f"conda={conda_version}")
conda_bin = "conda"
@@ -492,8 +492,8 @@ class InvolucroContext(installable.InstallableContext):
def __init__(
self,
- involucro_bin: Optional[str] = None,
- shell_exec: Optional[Callable[[List[str]], int]] = None,
+ involucro_bin: str | None = None,
+ shell_exec: Callable[[list[str]], int] | None = None,
verbose: str = "3",
) -> None:
if involucro_bin is None:
@@ -506,11 +506,11 @@ class InvolucroContext(installable.InstallableContext):
self.shell_exec = shell_exec or commands.shell
self.verbose = verbose
- def build_command(self, involucro_args: List[str]) -> List[str]:
+ def build_command(self, involucro_args: list[str]) -> list[str]:
cmd = [self.involucro_bin, f"-v={self.verbose}"]
return cmd + involucro_args
- def exec_command(self, involucro_args: List[str]) -> int:
+ def exec_command(self, involucro_args: list[str]) -> int:
cmd = self.build_command(involucro_args)
# Create ./build dir manually, otherwise Docker will do it as root
created_build_dir = False
@@ -643,7 +643,7 @@ def add_single_image_arguments(parser):
)
-def target_str_to_targets(targets_raw: str) -> List[CondaTarget]:
+def target_str_to_targets(targets_raw: str) -> list[CondaTarget]:
def parse_target(target_str: str) -> CondaTarget:
if "=" in target_str:
package_name, version_str = target_str.split("=", 1)
diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_build_files.py b/lib/galaxy/tool_util/deps/mulled/mulled_build_files.py
index 27bc2ba0e22..3d97b8e5023 100644
--- a/lib/galaxy/tool_util/deps/mulled/mulled_build_files.py
+++ b/lib/galaxy/tool_util/deps/mulled/mulled_build_files.py
@@ -13,14 +13,14 @@ Build all recipes discovered in tsv files in a single directory.
"""
import sys
+from collections.abc import (
+ Iterator,
+ Sequence,
+)
from dataclasses import dataclass
from pathlib import Path
from typing import (
Any,
- Iterator,
- List,
- Optional,
- Sequence,
)
from galaxy.tool_util.deps.conda_util import CondaTarget
@@ -39,10 +39,10 @@ FALLBACK_FIELD_ORDER = ("targets", "image_build", "name_override", "base_image")
@dataclass
class Target:
- targets: List[CondaTarget]
- image_build: Optional[str]
- name_override: Optional[str]
- base_image: Optional[str]
+ targets: list[CondaTarget]
+ image_build: str | None
+ name_override: str | None
+ base_image: str | None
def main(argv=None):
@@ -96,7 +96,7 @@ def generate_targets(target_source) -> Iterator[Target]:
yield line_to_targets(line, field_order)
-def field_order_from_header(header: str) -> List[str]:
+def field_order_from_header(header: str) -> list[str]:
fields = header[1:].split("\t")
for field in fields:
assert field in KNOWN_FIELDS, f"'{field}' is not one of {KNOWN_FIELDS}"
@@ -109,7 +109,7 @@ def field_order_from_header(header: str) -> List[str]:
def line_to_targets(line_str: str, field_order: Sequence[str]) -> Target:
"""Parse a line so that some columns can remain unspecified."""
- line_parts: List[Any] = line_str.split("\t")
+ line_parts: list[Any] = line_str.split("\t")
n_fields = len(field_order)
targets_column = field_order.index("targets")
assert (
diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py b/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py
index c3064f570a4..8dc430c58bc 100644
--- a/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py
+++ b/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py
@@ -10,7 +10,6 @@ Build mulled images for requirements defined in a tool:
"""
from typing import (
- List,
TYPE_CHECKING,
)
@@ -48,7 +47,7 @@ def main(argv=None) -> None:
_mulled_build_tool(args.tool, args)
-def requirements_to_mulled_targets(requirements) -> List["CondaTarget"]:
+def requirements_to_mulled_targets(requirements) -> list["CondaTarget"]:
"""Convert Galaxy's representation of requirements into a list of CondaTarget objects.
Only package requirements are retained.
diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_hash.py b/lib/galaxy/tool_util/deps/mulled/mulled_hash.py
index f847c4914f5..d06a2d83ebf 100644
--- a/lib/galaxy/tool_util/deps/mulled/mulled_hash.py
+++ b/lib/galaxy/tool_util/deps/mulled/mulled_hash.py
@@ -8,7 +8,7 @@ Produce a mulled hash with:
mulled-hash samtools=1.3.1,bedtools=2.22
"""
-from typing_extensions import Literal
+from typing import Literal
from ._cli import arg_parser
from .mulled_build import target_str_to_targets
diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_search.py b/lib/galaxy/tool_util/deps/mulled/mulled_search.py
index 16d64ce3411..126303484e6 100755
--- a/lib/galaxy/tool_util/deps/mulled/mulled_search.py
+++ b/lib/galaxy/tool_util/deps/mulled/mulled_search.py
@@ -7,10 +7,6 @@ import os
import sys
import tempfile
import time
-from typing import (
- Dict,
- List,
-)
from galaxy.tool_util.deps.conda_util import CondaContext
from galaxy.util import (
@@ -163,7 +159,7 @@ class CondaSearch:
def __init__(self, channel):
self.channel = channel
- def get_json(self, search_string) -> List[Dict[str, str]]:
+ def get_json(self, search_string) -> list[dict[str, str]]:
"""
Function takes search_string variable and returns results from the bioconda channel in JSON format
@@ -177,7 +173,7 @@ class CondaSearch:
logging.info(f"Search failed with: {e}")
return []
header_found = False
- lines_fields: List[List[str]] = []
+ lines_fields: list[list[str]] = []
for line in raw_out.splitlines():
if line.startswith("#"):
header_found = True
diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_update_singularity_containers.py b/lib/galaxy/tool_util/deps/mulled/mulled_update_singularity_containers.py
index b1fd62feed8..850a5058ee5 100644
--- a/lib/galaxy/tool_util/deps/mulled/mulled_update_singularity_containers.py
+++ b/lib/galaxy/tool_util/deps/mulled/mulled_update_singularity_containers.py
@@ -8,8 +8,6 @@ from glob import glob
from subprocess import check_output
from typing import (
Any,
- Dict,
- List,
)
from galaxy.util import unicodify
@@ -45,12 +43,12 @@ def docker_to_singularity(container, installation, filepath, no_sudo=False):
def singularity_container_test(
- tests: Dict[str, Dict[str, Any]], installation: str, filepath: StrPath
-) -> Dict[str, List]:
+ tests: dict[str, dict[str, Any]], installation: str, filepath: StrPath
+) -> dict[str, list]:
"""
Run tests, record if they pass or fail
"""
- test_results: Dict[str, List] = {"passed": [], "failed": [], "notest": []}
+ test_results: dict[str, list] = {"passed": [], "failed": [], "notest": []}
# create a 'sanitised home' directory in which the containers may be mounted - see http://singularity.lbl.gov/faq#solution-1-specify-the-home-to-mount
with tempfile.TemporaryDirectory() as tmpdirname:
diff --git a/lib/galaxy/tool_util/deps/mulled/util.py b/lib/galaxy/tool_util/deps/mulled/util.py
index 5e7b8f9530f..0753925ce54 100644
--- a/lib/galaxy/tool_util/deps/mulled/util.py
+++ b/lib/galaxy/tool_util/deps/mulled/util.py
@@ -7,16 +7,15 @@ import os
import re
import sys
import threading
+from collections.abc import (
+ Callable,
+ Iterable,
+)
from typing import (
Any,
- Callable,
- Dict,
- Iterable,
- List,
NamedTuple,
Optional,
TYPE_CHECKING,
- Union,
)
from conda_package_streaming.package_streaming import stream_conda_info
@@ -51,12 +50,12 @@ CONDA_IMAGE = os.environ.get("CONDA_IMAGE", "quay.io/condaforge/miniforge3:lates
class PARSED_TAG(NamedTuple):
tag: str
- version: Union[LegacyVersion, Version]
- build_string: Union[LegacyVersion, Version]
+ version: LegacyVersion | Version
+ build_string: LegacyVersion | Version
build_number: int
-def default_mulled_conda_channels_from_env() -> Optional[List[str]]:
+def default_mulled_conda_channels_from_env() -> list[str] | None:
if "DEFAULT_MULLED_CONDA_CHANNELS" in os.environ:
return os.environ["DEFAULT_MULLED_CONDA_CHANNELS"].split(",")
else:
@@ -69,12 +68,12 @@ DEFAULT_CHANNELS = default_mulled_conda_channels_from_env() or ["conda-forge", "
class CondaInDockerContext(CondaContext):
def __init__(
self,
- conda_prefix: Optional[str] = None,
- conda_exec: Optional[Union[str, List[str]]] = None,
- shell_exec: Optional[Callable[..., int]] = None,
+ conda_prefix: str | None = None,
+ conda_exec: str | list[str] | None = None,
+ shell_exec: Callable[..., int] | None = None,
debug: bool = False,
- ensure_channels: Union[str, List[str]] = DEFAULT_CHANNELS,
- condarc_override: Optional[str] = None,
+ ensure_channels: str | list[str] = DEFAULT_CHANNELS,
+ condarc_override: str | None = None,
):
if not conda_exec:
binds = []
@@ -106,7 +105,7 @@ def create_repository(namespace: str, repo_name: str, oauth_token: str) -> None:
response.raise_for_status()
-def quay_versions(namespace: str, pkg_name: str, session: Optional[Session] = None) -> List[str]:
+def quay_versions(namespace: str, pkg_name: str, session: Session | None = None) -> list[str]:
"""Get all version tags for a Docker image stored on quay.io for supplied package name."""
data = quay_repository(namespace, pkg_name, session=session)
@@ -119,7 +118,7 @@ def quay_versions(namespace: str, pkg_name: str, session: Optional[Session] = No
return [tag for tag in data["tags"].keys() if tag != "latest"]
-def quay_repository(namespace: str, pkg_name: str, session: Optional[Session] = None) -> Dict[str, Any]:
+def quay_repository(namespace: str, pkg_name: str, session: Session | None = None) -> dict[str, Any]:
assert namespace is not None
assert pkg_name is not None
url = f"{QUAY_REPOSITORY_API_ENDPOINT}/{namespace}/{pkg_name}"
@@ -131,7 +130,7 @@ def quay_repository(namespace: str, pkg_name: str, session: Optional[Session] =
return data
-def _get_namespace(namespace: str) -> List[str]:
+def _get_namespace(namespace: str) -> list[str]:
log.debug(f"Querying {QUAY_REPOSITORY_API_ENDPOINT} for repos within {namespace}")
next_page = None
repo_names = []
@@ -176,11 +175,11 @@ def _namespace_has_repo_name(namespace: str, repo_name: str, resolution_cache: "
def mulled_tags_for(
namespace: str,
image: str,
- tag_prefix: Optional[str] = None,
+ tag_prefix: str | None = None,
resolution_cache: Optional["ResolutionCache"] = None,
- session: Optional[Session] = None,
+ session: Session | None = None,
expire: float = QUAY_VERSIONS_CACHE_EXPIRY,
-) -> List[str]:
+) -> list[str]:
"""Fetch remote tags available for supplied image name.
The result will be sorted so newest tags are first.
@@ -223,7 +222,7 @@ def mulled_tags_for(
return tags
-def split_tag(tag: str) -> List[str]:
+def split_tag(tag: str) -> list[str]:
"""Split mulled image tag into conda version and conda build."""
return tag.rsplit("--", 1)
@@ -233,8 +232,7 @@ def parse_tag(tag: str) -> PARSED_TAG:
version = tag.rsplit(":")[-1]
build_string = "-1"
build_number = -1
- match = BUILD_NUMBER_REGEX.search(version)
- if match:
+ if match := BUILD_NUMBER_REGEX.search(version):
build_number = int(match.group(0))
if "--" in version:
version, build_string = version.rsplit("--", 1)
@@ -254,7 +252,7 @@ def parse_tag(tag: str) -> PARSED_TAG:
)
-def version_sorted(elements: Iterable[str]) -> List[str]:
+def version_sorted(elements: Iterable[str]) -> list[str]:
"""Sort iterable based on loose description of "version" from newest to oldest."""
parsed_tags_iter = (parse_tag(tag) for tag in elements)
sorted_tags = sorted(parsed_tags_iter, key=lambda tag: tag.build_string, reverse=True)
@@ -264,7 +262,7 @@ def version_sorted(elements: Iterable[str]) -> List[str]:
def build_target(
- package_name: str, version: Optional[str] = None, build: Optional[str] = None, tag: Optional[str] = None
+ package_name: str, version: str | None = None, build: str | None = None, tag: str | None = None
) -> CondaTarget:
"""Use supplied arguments to build a :class:`CondaTarget` object."""
if tag is not None:
@@ -287,7 +285,7 @@ def conda_build_target_str(target: CondaTarget) -> str:
return rval
-def _simple_image_name(targets: List[CondaTarget], image_build: Optional[str] = None) -> str:
+def _simple_image_name(targets: list[CondaTarget], image_build: str | None = None) -> str:
target = targets[0]
suffix = ""
if target.version is not None:
@@ -303,7 +301,7 @@ def _simple_image_name(targets: List[CondaTarget], image_build: Optional[str] =
def v1_image_name(
- targets: Iterable[CondaTarget], image_build: Optional[str] = None, name_override: Optional[str] = None
+ targets: Iterable[CondaTarget], image_build: str | None = None, name_override: str | None = None
) -> str:
"""Generate mulled hash version 1 container identifier for supplied arguments.
@@ -344,7 +342,7 @@ def v1_image_name(
def v2_image_name(
- targets: Iterable[CondaTarget], image_build: Optional[str] = None, name_override: Optional[str] = None
+ targets: Iterable[CondaTarget], image_build: str | None = None, name_override: str | None = None
) -> str:
"""Generate mulled hash version 2 container identifier for supplied arguments.
@@ -418,7 +416,7 @@ def v2_image_name(
return f"mulled-v2-{package_hash.hexdigest()}{suffix}"
-def get_files_from_conda_package(url: str, filepaths: Iterable[str]) -> Dict[str, bytes]:
+def get_files_from_conda_package(url: str, filepaths: Iterable[str]) -> dict[str, bytes]:
"""
Get content of specified files in a conda package.
The url can be a path to a local file or an url.
@@ -445,7 +443,7 @@ def get_files_from_conda_package(url: str, filepaths: Iterable[str]) -> Dict[str
return ret
-def split_container_name(name: str) -> List[str]:
+def split_container_name(name: str) -> list[str]:
"""
Takes a container name (e.g. samtools:1.7--1) and returns a list (e.g. ['samtools', '1.7', '1'])
>>> split_container_name('samtools:1.7--1')
diff --git a/lib/galaxy/tool_util/deps/requirements.py b/lib/galaxy/tool_util/deps/requirements.py
index 3c345068ae8..f9b0f3a628f 100644
--- a/lib/galaxy/tool_util/deps/requirements.py
+++ b/lib/galaxy/tool_util/deps/requirements.py
@@ -1,19 +1,13 @@
import copy
import os
-from typing import (
- Any,
+from collections.abc import (
Callable,
- cast,
- Dict,
Iterable,
Iterator,
- List,
- Optional,
- Tuple,
- Union,
)
-
-from typing_extensions import (
+from typing import (
+ Any,
+ cast,
get_args,
Literal,
)
@@ -40,9 +34,9 @@ class ToolRequirement:
def __init__(
self,
name: str,
- type: Optional[str] = None,
- version: Optional[str] = None,
- specs: Optional[Iterable["RequirementSpecification"]] = None,
+ type: str | None = None,
+ version: str | None = None,
+ specs: Iterable["RequirementSpecification"] | None = None,
) -> None:
if specs is None:
specs = []
@@ -51,7 +45,7 @@ class ToolRequirement:
self.version = version
self.specs = specs
- def to_dict(self) -> Dict[str, Any]:
+ def to_dict(self) -> dict[str, Any]:
specs = [s.to_dict() for s in self.specs]
return dict(name=self.name, type=self.type, version=self.version, specs=specs)
@@ -59,7 +53,7 @@ class ToolRequirement:
return copy.deepcopy(self)
@classmethod
- def from_dict(cls, d: Dict[str, Any]) -> "ToolRequirement":
+ def from_dict(cls, d: dict[str, Any]) -> "ToolRequirement":
version = d.get("version")
name = d["name"]
type = d.get("type")
@@ -86,7 +80,7 @@ class ToolRequirement:
class RequirementSpecification:
"""Refine a requirement using a URI."""
- def __init__(self, uri: str, version: Optional[str] = None) -> None:
+ def __init__(self, uri: str, version: str | None = None) -> None:
self.uri = uri
self.version = version
@@ -98,11 +92,11 @@ class RequirementSpecification:
def short_name(self) -> str:
return self.uri.split("/")[-1]
- def to_dict(self) -> Dict[str, Any]:
+ def to_dict(self) -> dict[str, Any]:
return dict(uri=self.uri, version=self.version)
@classmethod
- def from_dict(cls, dict: Dict) -> "RequirementSpecification":
+ def from_dict(cls, dict: dict) -> "RequirementSpecification":
uri = dict["uri"]
version = dict.get("version", None)
return cls(uri=uri, version=version)
@@ -119,7 +113,7 @@ class ToolRequirements:
Represents all requirements (packages, env vars) needed to run a tool.
"""
- def __init__(self, tool_requirements: Optional[List[Union[ToolRequirement, Dict[str, Any]]]] = None) -> None:
+ def __init__(self, tool_requirements: list[ToolRequirement | dict[str, Any]] | None = None) -> None:
if tool_requirements:
if not isinstance(tool_requirements, list):
raise ToolRequirementsException("ToolRequirements Constructor expects a list")
@@ -130,7 +124,7 @@ class ToolRequirements:
self.tool_requirements = OrderedSet()
@classmethod
- def from_list(cls, requirements: List[Union[ToolRequirement, Dict[str, Any]]]) -> "ToolRequirements":
+ def from_list(cls, requirements: list[ToolRequirement | dict[str, Any]]) -> "ToolRequirements":
return cls(requirements)
@property
@@ -144,7 +138,7 @@ class ToolRequirements:
def to_list(self):
return [r.to_dict() for r in self.tool_requirements]
- def append(self, requirement: Union[ToolRequirement, Dict[str, Any]]) -> None:
+ def append(self, requirement: ToolRequirement | dict[str, Any]) -> None:
if not isinstance(requirement, ToolRequirement):
requirement = ToolRequirement.from_dict(requirement)
self.tool_requirements.add(requirement)
@@ -168,7 +162,7 @@ class ToolRequirements:
def __hash__(self) -> int:
return sum(r.__hash__() for r in self.tool_requirements)
- def to_dict(self) -> List[Dict[str, Any]]:
+ def to_dict(self) -> list[dict[str, Any]]:
return [r.to_dict() for r in self.tool_requirements]
@@ -208,7 +202,7 @@ class ContainerDescription:
self.shell = shell
self.explicit = False
- def to_dict(self, *args, **kwds) -> Dict[str, Any]:
+ def to_dict(self, *args, **kwds) -> dict[str, Any]:
return dict(
identifier=self.identifier,
type=self.type,
@@ -217,7 +211,7 @@ class ContainerDescription:
)
@classmethod
- def from_dict(cls, dict: Dict[str, Any]) -> "ContainerDescription":
+ def from_dict(cls, dict: dict[str, Any]) -> "ContainerDescription":
identifier = dict["identifier"]
type = dict.get("type", DEFAULT_CONTAINER_TYPE)
resolve_dependencies = dict.get("resolve_dependencies", DEFAULT_CONTAINER_RESOLVE_DEPENDENCIES)
@@ -252,7 +246,7 @@ VALID_RESOURCE_TYPES = get_args(ResourceType)
class ResourceRequirement:
- def __init__(self, value_or_expression: Union[int, float, str], resource_type: ResourceType) -> None:
+ def __init__(self, value_or_expression: int | float | str, resource_type: ResourceType) -> None:
self.value_or_expression = value_or_expression
if not resource_type:
raise ValueError("Missing resource requirement type")
@@ -265,10 +259,10 @@ class ResourceRequirement:
except ValueError:
self.runtime_required = True
- def to_dict(self) -> Dict[str, Any]:
+ def to_dict(self) -> dict[str, Any]:
return {"resource_type": self.resource_type, "value_or_expression": self.value_or_expression}
- def get_value(self, runtime: Optional[Dict] = None, js_evaluator: Optional[Callable] = None) -> float:
+ def get_value(self, runtime: dict | None = None, js_evaluator: Callable | None = None) -> float:
if self.runtime_required:
# TODO: hook up evaluator
# return js_evaluator(self.value_or_expression, runtime)
@@ -278,7 +272,7 @@ class ResourceRequirement:
return float(self.value_or_expression)
-def resource_requirements_from_list(requirements: Iterable[Dict[str, Any]]) -> List[ResourceRequirement]:
+def resource_requirements_from_list(requirements: Iterable[dict[str, Any]]) -> list[ResourceRequirement]:
cwl_to_galaxy = {
"coresMin": "cores_min",
"coresMax": "cores_max",
@@ -334,7 +328,7 @@ class BaseCredential:
if not self.inject_as_env:
raise ValueError("Missing inject_as_env")
- def to_dict(self) -> Dict[str, Any]:
+ def to_dict(self) -> dict[str, Any]:
return {
"name": self.name,
"optional": self.optional,
@@ -375,8 +369,8 @@ class CredentialsRequirement:
label: str = "",
description: str = "",
optional: bool = False,
- secrets: Optional[List[Secret]] = None,
- variables: Optional[List[Variable]] = None,
+ secrets: list[Secret] | None = None,
+ variables: list[Variable] | None = None,
) -> None:
self.name = name
self.version = version
@@ -391,7 +385,7 @@ class CredentialsRequirement:
if not self.version:
raise ValueError("Missing version")
- def to_dict(self) -> Dict[str, Any]:
+ def to_dict(self) -> dict[str, Any]:
return {
"name": self.name,
"version": self.version,
@@ -403,7 +397,7 @@ class CredentialsRequirement:
}
@classmethod
- def from_dict(cls, dict: Dict[str, Any]) -> "CredentialsRequirement":
+ def from_dict(cls, dict: dict[str, Any]) -> "CredentialsRequirement":
name = dict["name"]
version = dict["version"]
label = dict.get("label", "")
@@ -423,17 +417,17 @@ class CredentialsRequirement:
def parse_requirements_from_lists(
- software_requirements: List[Union[ToolRequirement, Dict[str, Any]]],
- containers: Iterable[Dict[str, Any]],
- resource_requirements: Iterable[Dict[str, Any]],
- javascript_requirements: List[Dict[str, Any]],
- credentials: Iterable[Dict[str, Any]],
-) -> Tuple[
+ software_requirements: list[ToolRequirement | dict[str, Any]],
+ containers: Iterable[dict[str, Any]],
+ resource_requirements: Iterable[dict[str, Any]],
+ javascript_requirements: list[dict[str, Any]],
+ credentials: Iterable[dict[str, Any]],
+) -> tuple[
ToolRequirements,
- List[ContainerDescription],
- List[ResourceRequirement],
- List[JavascriptRequirement],
- List[CredentialsRequirement],
+ list[ContainerDescription],
+ list[ResourceRequirement],
+ list[JavascriptRequirement],
+ list[CredentialsRequirement],
]:
return (
ToolRequirements.from_list(software_requirements),
@@ -488,7 +482,7 @@ def parse_requirements_from_xml(xml_root, parse_resources_and_credentials: bool
if parse_resources_and_credentials:
resource_elems = requirements_elem.findall("resource") if requirements_elem is not None else []
resources = [resource_from_element(r) for r in resource_elems]
- javascript_requirements: List[Dict[str, Any]] = []
+ javascript_requirements: list[dict[str, Any]] = []
credentials_elems = requirements_elem.findall("credentials") if requirements_elem is not None else []
credentials = [credentials_from_element(s) for s in credentials_elems]
return requirements, containers, resources, javascript_requirements, credentials
diff --git a/lib/galaxy/tool_util/deps/resolvers/__init__.py b/lib/galaxy/tool_util/deps/resolvers/__init__.py
index 707e3e1cfa1..a8069550f4a 100644
--- a/lib/galaxy/tool_util/deps/resolvers/__init__.py
+++ b/lib/galaxy/tool_util/deps/resolvers/__init__.py
@@ -6,11 +6,7 @@ from abc import (
ABCMeta,
abstractmethod,
)
-from typing import (
- Any,
- Dict,
- List,
-)
+from typing import Any
import yaml
@@ -39,7 +35,7 @@ class DependencyResolver(Dictifiable, metaclass=ABCMeta):
# resolution.
disabled = False
resolves_simple_dependencies = True
- config_options: Dict[str, Any] = {}
+ config_options: dict[str, Any] = {}
read_only = True
@abstractmethod
@@ -76,7 +72,7 @@ class MultipleDependencyResolver:
"""Variant of DependencyResolver that can optionally resolve multiple dependencies together."""
@abstractmethod
- def resolve_all(self, requirements: ToolRequirements, **kwds) -> List["Dependency"]:
+ def resolve_all(self, requirements: ToolRequirements, **kwds) -> list["Dependency"]:
"""
Given multiple requirements yields a list of Dependency objects if and only if they may all be resolved together.
@@ -253,8 +249,7 @@ class SpecificationPatternDependencyResolver(SpecificationAwareDependencyResolve
version = requirement.version
specs = requirement.specs
- spec = self._find_specification(specs)
- if spec is not None:
+ if (spec := self._find_specification(specs)) is not None:
name = spec.short_name
version = spec.version or version
diff --git a/lib/galaxy/tool_util/deps/resolvers/conda.py b/lib/galaxy/tool_util/deps/resolvers/conda.py
index 450e0c1b6fd..22a2fbe3b30 100644
--- a/lib/galaxy/tool_util/deps/resolvers/conda.py
+++ b/lib/galaxy/tool_util/deps/resolvers/conda.py
@@ -6,10 +6,6 @@ incompatible changes coming.
import logging
import os
import re
-from typing import (
- List,
- Optional,
-)
import galaxy.tool_util.deps.installable
from galaxy.tool_util.deps.requirements import (
@@ -185,7 +181,7 @@ class CondaDependencyResolver(
final_return_code = return_code
return final_return_code
- def install_all(self, conda_targets: List[CondaTarget], env: str) -> bool:
+ def install_all(self, conda_targets: list[CondaTarget], env: str) -> bool:
if self.read_only:
return False
@@ -202,7 +198,7 @@ class CondaDependencyResolver(
return is_installed
- def resolve_all(self, requirements: ToolRequirements, **kwds) -> List[Dependency]:
+ def resolve_all(self, requirements: ToolRequirements, **kwds) -> list[Dependency]:
"""
Some combinations of tool requirements need to be resolved all at once, so that Conda can select a compatible
combination of dependencies. This method returns a list of MergedCondaDependency instances (one for each requirement)
@@ -252,7 +248,7 @@ class CondaDependencyResolver(
if install:
is_installed = self.install_all(conda_targets, env)
- dependencies: List[Dependency] = []
+ dependencies: list[Dependency] = []
if is_installed:
for requirement in requirements:
dependency = MergedCondaDependency(
@@ -268,7 +264,7 @@ class CondaDependencyResolver(
return dependencies
- def merged_environment_name(self, conda_targets: List[CondaTarget], capitalized_package_names: bool = False) -> str:
+ def merged_environment_name(self, conda_targets: list[CondaTarget], capitalized_package_names: bool = False) -> str:
if len(conda_targets) > 1:
# For continuity with mulled containers this is kind of nice.
return f"mulled-v1-{hash_conda_packages(conda_targets, capitalized_package_names)}"
@@ -412,9 +408,9 @@ class MergedCondaDependency(Dependency):
environment_path: str,
exact: bool,
name: str,
- version: Optional[str] = None,
+ version: str | None = None,
preserve_python_environment: bool = False,
- dependency_resolver: Optional[DependencyResolver] = None,
+ dependency_resolver: DependencyResolver | None = None,
) -> None:
self.activate = conda_context.activate
self.conda_context = conda_context
@@ -464,9 +460,9 @@ class CondaDependency(Dependency):
environment_path: str,
exact: bool,
name: str,
- version: Optional[str] = None,
+ version: str | None = None,
preserve_python_environment: bool = False,
- dependency_resolver: Optional[DependencyResolver] = None,
+ dependency_resolver: DependencyResolver | None = None,
) -> None:
self.activate = conda_context.activate
self.conda_context = conda_context
diff --git a/lib/galaxy/tool_util/deps/singularity_util.py b/lib/galaxy/tool_util/deps/singularity_util.py
index 77ee94a0365..5e95692e909 100644
--- a/lib/galaxy/tool_util/deps/singularity_util.py
+++ b/lib/galaxy/tool_util/deps/singularity_util.py
@@ -1,11 +1,7 @@
import os
import shlex
from typing import (
- List,
- Optional,
- Tuple,
TYPE_CHECKING,
- Union,
)
if TYPE_CHECKING:
@@ -29,11 +25,11 @@ DEFAULT_RUN_EXTRA_ARGUMENTS = None
def pull_mulled_singularity_command(
docker_image_identifier: str,
cache_directory: str,
- namespace: Optional[str] = None,
+ namespace: str | None = None,
singularity_cmd: str = DEFAULT_SINGULARITY_COMMAND,
sudo: bool = DEFAULT_SUDO,
sudo_cmd: str = DEFAULT_SUDO_COMMAND,
-) -> List[str]:
+) -> list[str]:
command_parts = []
command_parts += _singularity_prefix(
singularity_cmd=singularity_cmd,
@@ -55,7 +51,7 @@ def pull_singularity_command(
singularity_cmd: str = DEFAULT_SINGULARITY_COMMAND,
sudo: bool = DEFAULT_SUDO,
sudo_cmd: str = DEFAULT_SUDO_COMMAND,
-) -> List[str]:
+) -> list[str]:
# Make sure cache dir exists
dirname = os.path.dirname(os.path.normpath(cache_path))
os.makedirs(dirname, exist_ok=True)
@@ -67,20 +63,20 @@ def pull_singularity_command(
def build_singularity_run_command(
container_command: str,
image: str,
- volumes: Optional[List["DockerVolume"]] = None,
- env: Optional[List[Tuple[str, str]]] = None,
- working_directory: Optional[str] = DEFAULT_WORKING_DIRECTORY,
+ volumes: list["DockerVolume"] | None = None,
+ env: list[tuple[str, str]] | None = None,
+ working_directory: str | None = DEFAULT_WORKING_DIRECTORY,
singularity_cmd: str = DEFAULT_SINGULARITY_COMMAND,
- run_extra_arguments: Optional[str] = DEFAULT_RUN_EXTRA_ARGUMENTS,
+ run_extra_arguments: str | None = DEFAULT_RUN_EXTRA_ARGUMENTS,
sudo: bool = DEFAULT_SUDO,
sudo_cmd: str = DEFAULT_SUDO_COMMAND,
- guest_ports: Union[bool, List[str]] = False,
- container_name: Optional[str] = None,
+ guest_ports: bool | list[str] = False,
+ container_name: str | None = None,
cleanenv: bool = DEFAULT_CLEANENV,
ipc: bool = DEFAULT_IPC,
pid: bool = DEFAULT_PID,
contain: bool = DEFAULT_CONTAIN,
- no_mount: Optional[List[str]] = DEFAULT_NO_MOUNT,
+ no_mount: list[str] | None = DEFAULT_NO_MOUNT,
) -> str:
volumes = volumes or []
env = env or []
@@ -128,7 +124,7 @@ def _singularity_prefix(
sudo: bool = DEFAULT_SUDO,
sudo_cmd: str = DEFAULT_SUDO_COMMAND,
**kwds,
-) -> List[str]:
+) -> list[str]:
"""Prefix to issue a singularity command."""
command_parts = []
if sudo:
diff --git a/lib/galaxy/tool_util/deps/views.py b/lib/galaxy/tool_util/deps/views.py
index 8f5d462f367..172dc2a29ae 100644
--- a/lib/galaxy/tool_util/deps/views.py
+++ b/lib/galaxy/tool_util/deps/views.py
@@ -1,8 +1,5 @@
from typing import (
Any,
- Dict,
- List,
- Optional,
TYPE_CHECKING,
)
@@ -353,16 +350,16 @@ class ContainerResolutionView:
def __init__(self, app: "StructuredApp"):
self._app = app
- def index(self) -> List[Dict[str, Any]]:
+ def index(self) -> list[dict[str, Any]]:
return [r.to_dict() for r in self._container_resolvers]
- def show(self, index: str) -> Dict[str, Any]:
+ def show(self, index: str) -> dict[str, Any]:
return self._container_resolver(int(index)).to_dict()
- def resolve(self, index: Optional[str] = None, **kwds) -> Dict[str, Any]:
+ def resolve(self, index: str | None = None, **kwds) -> dict[str, Any]:
class ResolveKwds(TypedDict):
install: bool
- enabled_container_types: List["str"]
+ enabled_container_types: list["str"]
tool_info: "ToolInfo"
resolution_cache: NotRequired["ResolutionCache"]
session: NotRequired["Session"]
@@ -413,7 +410,7 @@ class ContainerResolutionView:
status = NullDependency().to_dict()
return {"tool_id": kwds["tool_id"], "status": status, "requirements": requirements.to_dict()}
- def resolve_toolbox(self, **kwds) -> List[Dict[str, Any]]:
+ def resolve_toolbox(self, **kwds) -> list[dict[str, Any]]:
rval = []
resolve_kwds = kwds.copy()
tool_ids = pop_tool_ids(resolve_kwds)
@@ -429,14 +426,14 @@ class ContainerResolutionView:
return rval
@property
- def _container_resolvers(self) -> List["ContainerResolver"]:
+ def _container_resolvers(self) -> list["ContainerResolver"]:
return self._app.container_finder.default_container_registry.container_resolvers
def _container_resolver(self, index: int):
return self._container_resolvers[index]
-def pop_tool_ids(kwds: Dict[str, Any]) -> Optional[List[str]]:
+def pop_tool_ids(kwds: dict[str, Any]) -> list[str] | None:
tool_ids = None
if "tool_ids" in kwds:
tool_ids = listify(kwds.pop("tool_ids"))
diff --git a/lib/galaxy/tool_util/edam_util.py b/lib/galaxy/tool_util/edam_util.py
index 514a551a5c7..6145728c000 100644
--- a/lib/galaxy/tool_util/edam_util.py
+++ b/lib/galaxy/tool_util/edam_util.py
@@ -1,7 +1,5 @@
import os
from typing import (
- Dict,
- Optional,
TextIO,
)
@@ -16,7 +14,7 @@ ROOT_OPERATION = "operation_0004"
ROOT_TOPIC = "topic_0003"
-def load_edam_tree(path: Optional[str] = None, *included_terms: str):
+def load_edam_tree(path: str | None = None, *included_terms: str):
if path is not None:
assert os.path.exists(path), f"Failed to load EDAM tabular data at [{path}] path does not exist."
handle = open(path)
@@ -29,7 +27,7 @@ def load_edam_tree(path: Optional[str] = None, *included_terms: str):
def load_edam_tree_from_tsv_stream(tsv_stream: TextIO, *included_terms: str):
- edam: Dict[str, Dict] = {}
+ edam: dict[str, dict] = {}
def _recurse_edam_parents(term, path=None):
if edam[term]["parents"] and len(edam[term]["parents"]) > 0:
diff --git a/lib/galaxy/tool_util/fetcher.py b/lib/galaxy/tool_util/fetcher.py
index 9e5ed42aeba..8879ebe9e43 100644
--- a/lib/galaxy/tool_util/fetcher.py
+++ b/lib/galaxy/tool_util/fetcher.py
@@ -1,7 +1,5 @@
import os
from typing import (
- Dict,
- Type,
TYPE_CHECKING,
)
@@ -16,7 +14,7 @@ class ToolLocationFetcher:
def __init__(self):
self.resolver_classes = self.__resolvers_dict()
- def __resolvers_dict(self) -> Dict[str, Type["ToolLocationResolver"]]:
+ def __resolvers_dict(self) -> dict[str, type["ToolLocationResolver"]]:
import galaxy.tool_util.locations
return plugin_config.plugins_dict(galaxy.tool_util.locations, "scheme")
diff --git a/lib/galaxy/tool_util/lint.py b/lib/galaxy/tool_util/lint.py
index 5a2097962e6..0728438b11b 100644
--- a/lib/galaxy/tool_util/lint.py
+++ b/lib/galaxy/tool_util/lint.py
@@ -49,15 +49,11 @@ from abc import (
ABC,
abstractmethod,
)
+from collections.abc import Callable
from enum import IntEnum
from typing import (
- Callable,
- List,
- Optional,
- Type,
TYPE_CHECKING,
TypeVar,
- Union,
)
import galaxy.tool_util.linters
@@ -104,14 +100,14 @@ class Linter(ABC):
return cls.__name__
@classmethod
- def list_linters(cls) -> List[str]:
+ def list_linters(cls) -> list[str]:
"""
list the names of all linter derived from Linter
"""
submodules.import_submodules(galaxy.tool_util.linters)
return [s.__name__ for s in cls.__subclasses__()]
- list_listers: Callable[[], List[str]] # deprecated alias
+ list_listers: Callable[[], list[str]] # deprecated alias
# Define the `list_listers` alias outside of the `Linter` class so that
@@ -125,7 +121,7 @@ class LintMessage:
a message from the linter
"""
- def __init__(self, level: str, message: str, linter: Optional[str] = None, **kwargs):
+ def __init__(self, level: str, message: str, linter: str | None = None, **kwargs):
self.level = level
self.message = message
self.linter = linter
@@ -156,7 +152,7 @@ class LintMessage:
class XMLLintMessageLine(LintMessage):
- def __init__(self, level: str, message: str, linter: Optional[str] = None, node: Optional[Element] = None):
+ def __init__(self, level: str, message: str, linter: str | None = None, node: Element | None = None):
super().__init__(level, message, linter)
self.line = None
if node is not None:
@@ -172,7 +168,7 @@ class XMLLintMessageLine(LintMessage):
class XMLLintMessageXPath(LintMessage):
- def __init__(self, level: str, message: str, linter: Optional[str] = None, node: Optional[Element] = None):
+ def __init__(self, level: str, message: str, linter: str | None = None, node: Element | None = None):
super().__init__(level, message, linter)
self.xpath = None
if node is not None:
@@ -193,18 +189,18 @@ LintTargetType = TypeVar("LintTargetType")
# it is reused for repositories in planemo. Therefore, it should probably
# be moved to galaxy.util.lint.
class LintContext:
- skip_types: List[str]
+ skip_types: list[str]
level: LintLevel
- lint_message_class: Type[LintMessage]
- object_name: Optional[str]
- message_list: List[LintMessage]
+ lint_message_class: type[LintMessage]
+ object_name: str | None
+ message_list: list[LintMessage]
def __init__(
self,
- level: Union[LintLevel, str],
- lint_message_class: Type[LintMessage] = LintMessage,
- skip_types: Optional[List[str]] = None,
- object_name: Optional[str] = None,
+ level: LintLevel | str,
+ lint_message_class: type[LintMessage] = LintMessage,
+ skip_types: list[str] | None = None,
+ object_name: str | None = None,
):
self.skip_types = skip_types or []
if isinstance(level, str):
@@ -228,7 +224,7 @@ class LintContext:
name: str,
lint_func: Callable[[LintTargetType, "LintContext"], None],
lint_target: LintTargetType,
- module_name: Optional[str] = None,
+ module_name: str | None = None,
):
if name.startswith("lint_"):
name = name[len("lint_") :]
@@ -266,39 +262,39 @@ class LintContext:
self.message_list = tmp_message_list + self.message_list
@property
- def valid_messages(self) -> List[LintMessage]:
+ def valid_messages(self) -> list[LintMessage]:
return [x for x in self.message_list if x.level == "check"]
@property
- def info_messages(self) -> List[LintMessage]:
+ def info_messages(self) -> list[LintMessage]:
return [x for x in self.message_list if x.level == "info"]
@property
- def warn_messages(self) -> List[LintMessage]:
+ def warn_messages(self) -> list[LintMessage]:
return [x for x in self.message_list if x.level == "warning"]
@property
- def error_messages(self) -> List[LintMessage]:
+ def error_messages(self) -> list[LintMessage]:
return [x for x in self.message_list if x.level == "error"]
- def __handle_message(self, level: str, message: str, linter: Optional[str] = None, *args, **kwargs) -> None:
+ def __handle_message(self, level: str, message: str, linter: str | None = None, *args, **kwargs) -> None:
if args:
message = message % args
self.message_list.append(self.lint_message_class(level=level, message=message, linter=linter, **kwargs))
- def valid(self, message: str, linter: Optional[str] = None, *args, **kwargs) -> None:
+ def valid(self, message: str, linter: str | None = None, *args, **kwargs) -> None:
self.__handle_message("check", message, linter, *args, **kwargs)
- def info(self, message: str, linter: Optional[str] = None, *args, **kwargs) -> None:
+ def info(self, message: str, linter: str | None = None, *args, **kwargs) -> None:
self.__handle_message("info", message, linter, *args, **kwargs)
- def error(self, message: str, linter: Optional[str] = None, *args, **kwargs) -> None:
+ def error(self, message: str, linter: str | None = None, *args, **kwargs) -> None:
self.__handle_message("error", message, linter, *args, **kwargs)
- def warn(self, message: str, linter: Optional[str] = None, *args, **kwargs) -> None:
+ def warn(self, message: str, linter: str | None = None, *args, **kwargs) -> None:
self.__handle_message("warning", message, linter, *args, **kwargs)
- def failed(self, fail_level: Union[LintLevel, str]) -> bool:
+ def failed(self, fail_level: LintLevel | str) -> bool:
if isinstance(fail_level, str):
fail_level = LintLevel[fail_level.upper()]
found_warns = self.found_warns
@@ -316,7 +312,7 @@ class LintContext:
NETWORK_LINTERS = ("BioToolsValid", "EDAMTermsValid")
-def lint_user_tool_source(user_tool_source: "UserToolSource") -> List[str]:
+def lint_user_tool_source(user_tool_source: "UserToolSource") -> list[str]:
"""Run the lint pipeline against a ``UserToolSource`` pydantic value.
Returns a list of formatted ``": "`` bullets at WARN
@@ -330,7 +326,7 @@ def lint_user_tool_source(user_tool_source: "UserToolSource") -> List[str]:
root_dict = user_tool_source.model_dump(by_alias=True, exclude_none=True)
tool_source = YamlToolSource(root_dict)
lint_context = get_lint_context_for_tool_source(tool_source, skip_types=list(NETWORK_LINTERS))
- bullets: List[str] = []
+ bullets: list[str] = []
for message in lint_context.error_messages + lint_context.warn_messages:
prefix = f"{message.linter}: " if message.linter else ""
bullets.append(f"{prefix}{message.message}")
diff --git a/lib/galaxy/tool_util/linters/command.py b/lib/galaxy/tool_util/linters/command.py
index eff900341cb..caea3e435b9 100644
--- a/lib/galaxy/tool_util/linters/command.py
+++ b/lib/galaxy/tool_util/linters/command.py
@@ -77,8 +77,7 @@ class CommandInfo(Linter):
command = tool_xml.find("./command")
if command is None:
return
- interpreter_type = command.attrib.get("interpreter", None)
interpreter_info = ""
- if interpreter_type:
+ if interpreter_type := command.attrib.get("interpreter", None):
interpreter_info = f" with interpreter of type [{interpreter_type}]"
lint_ctx.info(f"Tool contains a command{interpreter_info}.", linter=cls.name(), node=command)
diff --git a/lib/galaxy/tool_util/linters/containers.py b/lib/galaxy/tool_util/linters/containers.py
index 8401d103a6a..834eb25b8f7 100644
--- a/lib/galaxy/tool_util/linters/containers.py
+++ b/lib/galaxy/tool_util/linters/containers.py
@@ -1,9 +1,8 @@
"""Linter rules covering container references on a tool source."""
import re
+from collections.abc import Iterator
from typing import (
- Iterator,
- Tuple,
TYPE_CHECKING,
)
@@ -17,7 +16,7 @@ if TYPE_CHECKING:
lint_tool_types = ["*"]
-CONTAINER_PREFIXES: Tuple[str, ...] = ("quay.io/biocontainers/", "docker://", "oras://")
+CONTAINER_PREFIXES: tuple[str, ...] = ("quay.io/biocontainers/", "docker://", "oras://")
DOCKER_IMAGE_RE = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9._-]*(/[a-zA-Z0-9._-]+)*(:[\w][\w.-]*)?$")
diff --git a/lib/galaxy/tool_util/linters/datatypes.py b/lib/galaxy/tool_util/linters/datatypes.py
index c6b04c3b14c..84a400b5ee0 100644
--- a/lib/galaxy/tool_util/linters/datatypes.py
+++ b/lib/galaxy/tool_util/linters/datatypes.py
@@ -1,7 +1,6 @@
import os.path
from os import getenv
from typing import (
- Set,
TYPE_CHECKING,
Union,
)
@@ -24,7 +23,7 @@ if TYPE_CHECKING:
DATATYPES_CONF = getenv("DATATYPES_CONF", resource_path(__name__, "datatypes_conf.xml.sample"))
-def _parse_datatypes(datatype_conf_path: Union[str, "Traversable"]) -> Set[str]:
+def _parse_datatypes(datatype_conf_path: Union[str, "Traversable"]) -> set[str]:
datatypes = set()
tree = parse_xml(datatype_conf_path)
root = tree.getroot()
diff --git a/lib/galaxy/tool_util/linters/general.py b/lib/galaxy/tool_util/linters/general.py
index 624c18f7a90..9f07f5fbcc9 100644
--- a/lib/galaxy/tool_util/linters/general.py
+++ b/lib/galaxy/tool_util/linters/general.py
@@ -2,7 +2,6 @@
import re
from typing import (
- Tuple,
TYPE_CHECKING,
)
@@ -30,7 +29,7 @@ PROFILE_PATTERN = re.compile(r"^[12]\d\.\d{1,2}$")
lint_tool_types = ["*"]
-def _tool_xml_and_root(tool_source: "ToolSource") -> Tuple["ElementTree", "Element"]:
+def _tool_xml_and_root(tool_source: "ToolSource") -> tuple["ElementTree", "Element"]:
tool_xml = getattr(tool_source, "xml_tree", None)
if tool_xml:
tool_node = tool_xml.getroot()
@@ -241,7 +240,7 @@ class BioToolsValid(Linter):
continue
metadata_source = ApiBiotoolsMetadataSource()
if not metadata_source.get_biotools_metadata(xref["value"]):
- lint_ctx.warn(f'No entry {xref["value"]} in bio.tools.', linter=cls.name(), node=tool_node)
+ lint_ctx.warn(f"No entry {xref['value']} in bio.tools.", linter=cls.name(), node=tool_node)
class EDAMTermsValid(Linter):
diff --git a/lib/galaxy/tool_util/linters/help.py b/lib/galaxy/tool_util/linters/help.py
index 38f7be7c10d..de81e32a8b5 100644
--- a/lib/galaxy/tool_util/linters/help.py
+++ b/lib/galaxy/tool_util/linters/help.py
@@ -2,7 +2,6 @@
from typing import (
TYPE_CHECKING,
- Union,
)
from galaxy.tool_util.lint import Linter
@@ -86,8 +85,7 @@ class HelpInvalidRST(Linter):
help_text = help.text or ""
if not help_text.strip():
return
- invalid_rst = rst_invalid(help_text)
- if invalid_rst:
+ if invalid_rst := rst_invalid(help_text):
lint_ctx.warn(f"Invalid reStructuredText found in help - [{invalid_rst}].", linter=cls.name(), node=help)
@@ -108,13 +106,13 @@ class HelpValidRST(Linter):
lint_ctx.valid("Help contains valid reStructuredText.", linter=cls.name(), node=help)
-def rst_invalid(text: str) -> Union[bool, str]:
+def rst_invalid(text: str) -> bool | str:
"""
Predicate to determine if text is invalid reStructuredText.
Return False if the supplied text is valid reStructuredText or
a string indicating the problem.
"""
- invalid_rst: Union[bool, str] = False
+ invalid_rst: bool | str = False
try:
rst_to_html(text, error=True)
except Exception as e:
diff --git a/lib/galaxy/tool_util/linters/inputs.py b/lib/galaxy/tool_util/linters/inputs.py
index 925bf72b8e6..111cad29b92 100644
--- a/lib/galaxy/tool_util/linters/inputs.py
+++ b/lib/galaxy/tool_util/linters/inputs.py
@@ -3,11 +3,9 @@
import ast
import re
import warnings
+from collections.abc import Iterator
from copy import deepcopy
from typing import (
- Iterator,
- Optional,
- Tuple,
TYPE_CHECKING,
)
@@ -143,8 +141,7 @@ class InputsNum(Linter):
tool_node = tool_xml.find("./inputs")
if tool_node is None:
tool_node = tool_xml.getroot()
- num_inputs = len(tool_xml.findall("./inputs//param"))
- if num_inputs:
+ if num_inputs := len(tool_xml.findall("./inputs//param")):
lint_ctx.info(f"Found {num_inputs} input parameters.", linter=cls.name(), node=tool_node)
@@ -199,7 +196,7 @@ class InputsDatasourceTags(Linter):
)
-def _iter_param(tool_xml: "ElementTree") -> Iterator[Tuple["Element", str]]:
+def _iter_param(tool_xml: "ElementTree") -> Iterator[tuple["Element", str]]:
for param in tool_xml.findall("./inputs//param"):
if "name" not in param.attrib and "argument" not in param.attrib:
continue
@@ -207,7 +204,7 @@ def _iter_param(tool_xml: "ElementTree") -> Iterator[Tuple["Element", str]]:
yield param, param_name
-def _iter_param_type(tool_xml: "ElementTree") -> Iterator[Tuple["Element", str, str]]:
+def _iter_param_type(tool_xml: "ElementTree") -> Iterator[tuple["Element", str, str]]:
for param, param_name in _iter_param(tool_xml):
if "type" not in param.attrib:
continue
@@ -343,7 +340,7 @@ class InputsNameDuplicateOutput(Linter):
for output in outputs:
if output.get("name") in input_names:
lint_ctx.error(
- f'Tool defines an output with a name equal to the name of an input: \'{output.get("name")}\'',
+ f"Tool defines an output with a name equal to the name of an input: '{output.get('name')}'",
linter=cls.name(),
node=output,
)
@@ -1145,7 +1142,7 @@ class InputsSelectOptionalRadio(Linter):
)
-def _iter_param_validator(tool_xml: "ElementTree") -> Iterator[Tuple[str, str, "Element", str]]:
+def _iter_param_validator(tool_xml: "ElementTree") -> Iterator[tuple[str, str, "Element", str]]:
input_params = tool_xml.findall("./inputs//param[@type]")
for param in input_params:
try:
@@ -1435,7 +1432,7 @@ class ValidatorMetadataName(Linter):
)
-def _iter_conditional(tool_xml: "ElementTree") -> Iterator[Tuple["Element", Optional[str], "Element", Optional[str]]]:
+def _iter_conditional(tool_xml: "ElementTree") -> Iterator[tuple["Element", str | None, "Element", str | None]]:
conditionals = tool_xml.findall("./inputs//conditional")
for conditional in conditionals:
conditional_name = conditional.get("name")
diff --git a/lib/galaxy/tool_util/linters/output.py b/lib/galaxy/tool_util/linters/output.py
index 428eb6670bb..88cf58f27bf 100644
--- a/lib/galaxy/tool_util/linters/output.py
+++ b/lib/galaxy/tool_util/linters/output.py
@@ -41,8 +41,7 @@ class OutputsOutput(Linter):
tool_xml = getattr(tool_source, "xml_tree", None)
if not tool_xml:
return
- output = tool_xml.find("./outputs/output")
- if output is not None:
+ if (output := tool_xml.find("./outputs/output")) is not None:
lint_ctx.warn(
"Avoid the use of 'output' and replace by 'data' or 'collection'", linter=cls.name(), node=output
)
@@ -57,7 +56,7 @@ class OutputsNameInvalidCheetah(Linter):
for output in tool_xml.findall("./outputs/data[@name]") + tool_xml.findall("./outputs/collection[@name]"):
if not is_valid_cheetah_placeholder(output.attrib["name"]):
lint_ctx.warn(
- f'Tool output name [{output.attrib["name"]}] is not a valid Cheetah placeholder.',
+ f"Tool output name [{output.attrib['name']}] is not a valid Cheetah placeholder.",
linter=cls.name(),
node=output,
)
@@ -328,8 +327,7 @@ def _check_unqualified_reference(
)
else:
lint_ctx.error(
- f"Output '{output_name}' references {attr_name}='{ref_value}' "
- f"which does not match any input parameter.",
+ f"Output '{output_name}' references {attr_name}='{ref_value}' which does not match any input parameter.",
linter=linter_name,
node=node,
)
@@ -376,12 +374,10 @@ def _get_qualified_name(param_elem: "Element", parent_map: dict) -> str:
def _has_tool_provided_metadata(tool_xml: "ElementTree") -> bool:
- outputs = tool_xml.find("./outputs")
- if outputs is not None:
+ if (outputs := tool_xml.find("./outputs")) is not None:
if "provided_metadata_file" in outputs.attrib or "provided_metadata_style" in outputs.attrib:
return True
- command = tool_xml.find("./command")
- if command is not None:
+ if (command := tool_xml.find("./command")) is not None:
if "galaxy.json" in command.text:
return True
config = tool_xml.find("./configfiles/configfile[@filename='galaxy.json']")
diff --git a/lib/galaxy/tool_util/linters/tests.py b/lib/galaxy/tool_util/linters/tests.py
index 653837d201a..18fde73f513 100644
--- a/lib/galaxy/tool_util/linters/tests.py
+++ b/lib/galaxy/tool_util/linters/tests.py
@@ -1,11 +1,8 @@
"""This module contains a linting functions for tool tests."""
+from collections.abc import Iterator
from io import StringIO
from typing import (
- Iterator,
- List,
- Set,
- Tuple,
TYPE_CHECKING,
)
@@ -215,7 +212,7 @@ def _cleanup_pydantic_error(error) -> str:
return new_error.getvalue().strip()
-def _collect_multiple_select_names(parameters: List["ToolParameterT"]) -> Set[str]:
+def _collect_multiple_select_names(parameters: list["ToolParameterT"]) -> set[str]:
return {
param.name
for param in iter_parameter_models(parameters)
@@ -648,7 +645,7 @@ class TestsValid(Linter):
lint_ctx.warn("No valid test(s) found.", linter=cls.name(), node=general_node)
-def _iter_tests(tests: List["Element"], valid: bool) -> Iterator[Tuple[int, "Element"]]:
+def _iter_tests(tests: list["Element"], valid: bool) -> Iterator[tuple[int, "Element"]]:
for test_idx, test in enumerate(tests, start=1):
is_valid = False
is_valid |= bool(set(test.attrib) & {"expect_failure", "expect_exit_code", "expect_num_outputs"})
diff --git a/lib/galaxy/tool_util/linters/xml_order.py b/lib/galaxy/tool_util/linters/xml_order.py
index 13132e909c4..9f38a48db14 100644
--- a/lib/galaxy/tool_util/linters/xml_order.py
+++ b/lib/galaxy/tool_util/linters/xml_order.py
@@ -5,7 +5,6 @@ https://github.com/galaxy-iuc/standards.
"""
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -70,7 +69,7 @@ class XMLOrder(Linter):
else:
tag_ordering = TAG_ORDER
last_tag = None
- last_key: Optional[int] = None
+ last_key: int | None = None
for elem in tool_root:
tag = elem.tag
if tag not in tag_ordering:
diff --git a/lib/galaxy/tool_util/model_factory.py b/lib/galaxy/tool_util/model_factory.py
index f5a6ce85bb5..df3b0ed5973 100644
--- a/lib/galaxy/tool_util/model_factory.py
+++ b/lib/galaxy/tool_util/model_factory.py
@@ -1,8 +1,6 @@
import math
from typing import (
Any,
- List,
- Type,
TypeVar,
)
@@ -30,7 +28,7 @@ def parse_tool(tool_source: ToolSource) -> ParsedTool:
P = TypeVar("P", bound=ParsedTool)
-def parse_tool_custom(tool_source: ToolSource, model_type: Type[P]) -> P:
+def parse_tool_custom(tool_source: ToolSource, model_type: type[P]) -> P:
id = tool_source.parse_id()
version = tool_source.parse_version()
name = tool_source.parse_name()
@@ -71,8 +69,8 @@ def parse_tool_custom(tool_source: ToolSource, model_type: Type[P]) -> P:
)
-def _parsed_requirements(tool_requirements, resource_requirements, javascript_requirements) -> List[Any]:
- parsed_requirements: List[Any] = []
+def _parsed_requirements(tool_requirements, resource_requirements, javascript_requirements) -> list[Any]:
+ parsed_requirements: list[Any] = []
for requirement in tool_requirements:
if requirement.type == "package":
parsed_requirements.append(
diff --git a/lib/galaxy/tool_util/ontologies/ontology_data.py b/lib/galaxy/tool_util/ontologies/ontology_data.py
index c3ab1bf93ae..655e1556688 100644
--- a/lib/galaxy/tool_util/ontologies/ontology_data.py
+++ b/lib/galaxy/tool_util/ontologies/ontology_data.py
@@ -3,11 +3,7 @@ from collections import defaultdict
from functools import lru_cache
from typing import (
cast,
- Dict,
- List,
NamedTuple,
- Optional,
- Tuple,
)
import yaml
@@ -20,12 +16,12 @@ from galaxy.util.resources import resource_string
log = logging.getLogger(__name__)
-def _multi_dict_mapping(content: str) -> Dict[str, List[str]]:
- mapping: Dict[str, List[str]] = {}
+def _multi_dict_mapping(content: str) -> dict[str, list[str]]:
+ mapping: dict[str, list[str]] = {}
for x in content.splitlines():
if x.startswith("#"):
continue
- key, value = cast(Tuple[str, str], tuple(x.split("\t")))
+ key, value = cast(tuple[str, str], tuple(x.split("\t")))
mapping.setdefault(key, []).append(value)
return mapping
@@ -41,8 +37,8 @@ TOOL_TAG_MAPPING_FILENAME = "tool_tag_mappings.yml"
@lru_cache(maxsize=1)
-def _biotools_mapping() -> Dict[str, List[str]]:
- mapping: Dict[str, List[str]] = defaultdict(list)
+def _biotools_mapping() -> dict[str, list[str]]:
+ mapping: dict[str, list[str]] = defaultdict(list)
for line in _read_ontology_data_text(BIOTOOLS_MAPPING_FILENAME).splitlines():
if not line.startswith("#"):
tool_id, xref = line.split("\t")
@@ -51,18 +47,18 @@ def _biotools_mapping() -> Dict[str, List[str]]:
@lru_cache(maxsize=1)
-def _edam_operation_mapping() -> Dict[str, List[str]]:
+def _edam_operation_mapping() -> dict[str, list[str]]:
return _multi_dict_mapping(_read_ontology_data_text(EDAM_OPERATION_MAPPING_FILENAME))
@lru_cache(maxsize=1)
-def _edam_topic_mapping() -> Dict[str, List[str]]:
+def _edam_topic_mapping() -> dict[str, list[str]]:
return _multi_dict_mapping(_read_ontology_data_text(EDAM_TOPIC_MAPPING_FILENAME))
-def _load_tool_tag_mapping(content: str) -> Dict[str, List[str]]:
+def _load_tool_tag_mapping(content: str) -> dict[str, list[str]]:
raw = cast(
- Dict[str, List[str]],
+ dict[str, list[str]],
(yaml.safe_load(content) or {}).get("tool_tags", {}),
)
# `Tool.all_ids` is built from lowercased tool ids (see `Tool.parse` in
@@ -73,21 +69,21 @@ def _load_tool_tag_mapping(content: str) -> Dict[str, List[str]]:
return {tool_id.lower(): tags for tool_id, tags in raw.items()}
-_TOOL_TAG_MAPPING_OVERRIDE: Optional[Dict[str, List[str]]] = None
+_TOOL_TAG_MAPPING_OVERRIDE: dict[str, list[str]] | None = None
-def _tool_tag_mapping() -> Dict[str, List[str]]:
+def _tool_tag_mapping() -> dict[str, list[str]]:
if _TOOL_TAG_MAPPING_OVERRIDE is not None:
return _TOOL_TAG_MAPPING_OVERRIDE
return _bundled_tool_tag_mapping()
@lru_cache(maxsize=1)
-def _bundled_tool_tag_mapping() -> Dict[str, List[str]]:
+def _bundled_tool_tag_mapping() -> dict[str, list[str]]:
return _load_tool_tag_mapping(_read_ontology_data_text(TOOL_TAG_MAPPING_FILENAME))
-def configure_tool_tag_mapping(file_path: Optional[str]) -> None:
+def configure_tool_tag_mapping(file_path: str | None) -> None:
"""Replace the in-memory curated tool → tag mapping.
Galaxy calls this once at startup with the value of the
@@ -114,10 +110,10 @@ def configure_tool_tag_mapping(file_path: Optional[str]) -> None:
class OntologyData(NamedTuple):
- xrefs: List[XrefDict]
- edam_operations: Optional[List[str]]
- edam_topics: Optional[List[str]]
- tool_tags: List[str]
+ xrefs: list[XrefDict]
+ edam_operations: list[str] | None
+ edam_topics: list[str] | None
+ tool_tags: list[str]
def biotools_reference(xrefs):
@@ -127,7 +123,7 @@ def biotools_reference(xrefs):
return None
-def legacy_biotools_external_reference(all_ids: List[str]) -> List[str]:
+def legacy_biotools_external_reference(all_ids: list[str]) -> list[str]:
biotools_mapping = _biotools_mapping()
for tool_id in all_ids:
if tool_id in biotools_mapping:
@@ -135,10 +131,10 @@ def legacy_biotools_external_reference(all_ids: List[str]) -> List[str]:
return []
-def curated_tool_tags(all_ids: List[str]) -> List[str]:
+def curated_tool_tags(all_ids: list[str]) -> list[str]:
mapping = _tool_tag_mapping()
seen = set()
- tags: List[str] = []
+ tags: list[str] = []
for tool_id in all_ids:
for tag in mapping.get(tool_id, []):
if tag not in seen:
@@ -148,7 +144,7 @@ def curated_tool_tags(all_ids: List[str]) -> List[str]:
def expand_ontology_data(
- tool_source: ToolSource, all_ids: List[str], biotools_metadata_source: Optional[BiotoolsMetadataSource]
+ tool_source: ToolSource, all_ids: list[str], biotools_metadata_source: BiotoolsMetadataSource | None
) -> OntologyData:
xrefs = tool_source.parse_xrefs()
has_biotools_reference = any(x["type"] == "bio.tools" for x in xrefs)
diff --git a/lib/galaxy/tool_util/output_checker.py b/lib/galaxy/tool_util/output_checker.py
index 2eb7d6c427d..5af13ea7a78 100644
--- a/lib/galaxy/tool_util/output_checker.py
+++ b/lib/galaxy/tool_util/output_checker.py
@@ -2,15 +2,11 @@ import re
from enum import Enum
from logging import getLogger
from typing import (
- List,
- Optional,
- Tuple,
+ Literal,
TYPE_CHECKING,
- Union,
)
from typing_extensions import (
- Literal,
NotRequired,
TypedDict,
)
@@ -39,15 +35,15 @@ JobMessageTypeLiteral = Literal["regex", "exit_code", "max_discovered_files"]
class JobMessage(TypedDict):
- desc: Optional[str]
- code_desc: NotRequired[Optional[str]]
+ desc: str | None
+ code_desc: NotRequired[str | None]
error_level: float # Literal[0, 1, 1.1, 2, 3, 4] - mypy doesn't like literal floats.
class RegexJobMessage(JobMessage):
type: Literal["regex"]
- stream: Optional[str]
- match: Optional[str]
+ stream: str | None
+ match: str | None
class ExitCodeJobMessage(JobMessage):
@@ -59,11 +55,11 @@ class MaxDiscoveredFilesJobMessage(JobMessage):
type: Literal["max_discovered_files"]
-AnyJobMessage = Union[ExitCodeJobMessage, RegexJobMessage, MaxDiscoveredFilesJobMessage]
+AnyJobMessage = ExitCodeJobMessage | RegexJobMessage | MaxDiscoveredFilesJobMessage
def check_output_regex(
- regex: "ToolStdioRegex", stream: str, stream_name: str, job_messages: List[AnyJobMessage], max_error_level: int
+ regex: "ToolStdioRegex", stream: str, stream_name: str, job_messages: list[AnyJobMessage], max_error_level: int
) -> int:
"""
check a single regex against a stream
@@ -83,12 +79,12 @@ def check_output_regex(
def check_output(
- stdio_regexes: List["ToolStdioRegex"],
- stdio_exit_codes: List["ToolStdioExitCode"],
+ stdio_regexes: list["ToolStdioRegex"],
+ stdio_exit_codes: list["ToolStdioExitCode"],
stdout: str,
stderr: str,
tool_exit_code: int,
-) -> Tuple[str, str, str, List[AnyJobMessage]]:
+) -> tuple[str, str, str, list[AnyJobMessage]]:
"""
Check the output of a tool - given the stdout, stderr, and the tool's
exit code, return DETECTED_JOB_STATE.OK if the tool exited successfully or
@@ -110,7 +106,7 @@ def check_output(
# messages are added it the order of detection
# If job is failed, track why.
- job_messages: List[AnyJobMessage] = []
+ job_messages: list[AnyJobMessage] = []
try:
# Check exit codes and match regular expressions against stdout and
@@ -212,7 +208,7 @@ def __regex_err_msg(match: re.Match, stream: str, regex: "ToolStdioRegex") -> Re
mstart = match.start()
mend = match.end()
if mend - mstart > 256:
- match_str = f"{match.string[mstart:mstart + 256]}..."
+ match_str = f"{match.string[mstart : mstart + 256]}..."
else:
match_str = match.string[mstart:mend]
diff --git a/lib/galaxy/tool_util/parameters/case.py b/lib/galaxy/tool_util/parameters/case.py
index 1d4de4225a0..a768f34d500 100644
--- a/lib/galaxy/tool_util/parameters/case.py
+++ b/lib/galaxy/tool_util/parameters/case.py
@@ -7,16 +7,10 @@ from re import compile
from typing import (
Any,
cast,
- Dict,
- FrozenSet,
- List,
- Optional,
- Set,
- Tuple,
+ Literal,
)
from packaging.version import Version
-from typing_extensions import Literal
from galaxy.tool_util.parser.interface import (
TestCollectionDef,
@@ -70,16 +64,16 @@ WARN_ON_UNTYPED_XML_STRINGS = False
@dataclass
class TestCaseStateAndWarnings:
tool_state: TestCaseToolState
- warnings: List[str]
- unhandled_inputs: List[str]
+ warnings: list[str]
+ unhandled_inputs: list[str]
@dataclass
class TestCaseStateValidationResult:
tool_state: TestCaseToolState
- warnings: List[str]
- validation_error: Optional[Exception]
- tool_parameter_bundle: List[ToolParameterT]
+ warnings: list[str]
+ validation_error: Exception | None
+ tool_parameter_bundle: list[ToolParameterT]
profile: str
def to_dict(self):
@@ -94,7 +88,7 @@ class TestCaseStateValidationResult:
}
-def legacy_from_string(parameter: ToolParameterT, value: Optional[Any], warnings: List[str], profile: str) -> Any:
+def legacy_from_string(parameter: ToolParameterT, value: Any | None, warnings: list[str], profile: str) -> Any:
"""Convert string values in XML test cases into typed variants.
This should only be used when parsing XML test cases into a TestCaseToolState object.
@@ -214,9 +208,9 @@ class LegacyTestInputResolver:
"""
inputs: ToolSourceTestInputs
- consumed_discriminators: FrozenSet[str] = frozenset()
+ consumed_discriminators: frozenset[str] = frozenset()
- def consuming(self, discriminator_name: Optional[str]) -> "LegacyTestInputResolver":
+ def consuming(self, discriminator_name: str | None) -> "LegacyTestInputResolver":
if discriminator_name is None:
return self
return replace(self, consumed_discriminators=self.consumed_discriminators | {discriminator_name})
@@ -224,7 +218,7 @@ class LegacyTestInputResolver:
def for_inputs(self, inputs: ToolSourceTestInputs) -> "LegacyTestInputResolver":
return replace(self, inputs=inputs)
- def input_for(self, flat_state_path: str) -> Optional[ToolSourceTestInput]:
+ def input_for(self, flat_state_path: str) -> ToolSourceTestInput | None:
# Discriminators consumed by enclosing conditionals are excluded from the loose fallbacks
# below, so a descendant's omitted discriminator does not re-match an ancestor's.
exclude = self.consumed_discriminators
@@ -291,16 +285,16 @@ class MergeContext:
resolver: LegacyTestInputResolver
profile: str
state_representation: Literal["test_case_xml", "test_case_json"]
- warnings: List[str]
+ warnings: list[str]
@property
def inputs(self) -> ToolSourceTestInputs:
return self.resolver.inputs
- def input_for(self, flat_state_path: str) -> Optional[ToolSourceTestInput]:
+ def input_for(self, flat_state_path: str) -> ToolSourceTestInput | None:
return self.resolver.input_for(flat_state_path)
- def consuming(self, discriminator_name: Optional[str]) -> "MergeContext":
+ def consuming(self, discriminator_name: str | None) -> "MergeContext":
return replace(self, resolver=self.resolver.consuming(discriminator_name))
def for_inputs(self, inputs: ToolSourceTestInputs) -> "MergeContext":
@@ -309,15 +303,15 @@ class MergeContext:
def test_case_state(
test_dict: ToolSourceTest,
- tool_parameter_bundle: List[ToolParameterT],
+ tool_parameter_bundle: list[ToolParameterT],
profile: str,
validate: bool = True,
- name: Optional[str] = None,
+ name: str | None = None,
) -> TestCaseStateAndWarnings:
- warnings: List[str] = []
+ warnings: list[str] = []
inputs: ToolSourceTestInputs = test_dict["inputs"]
unhandled_inputs = []
- state: Dict[str, Any] = {}
+ state: dict[str, Any] = {}
state_representation = test_dict.get("value_state_representation", "test_case_xml")
context = MergeContext(LegacyTestInputResolver(inputs), profile, state_representation, warnings)
@@ -337,7 +331,7 @@ def test_case_state(
return TestCaseStateAndWarnings(tool_state, warnings, unhandled_inputs)
-def _input_name_was_handled_by_legacy_fallback(input_name: str, handled_inputs: Set[str], profile: str) -> bool:
+def _input_name_was_handled_by_legacy_fallback(input_name: str, handled_inputs: set[str], profile: str) -> bool:
"""True if a pre-24.2 legacy fallback already covered input_name (loose suffix-match).
The match is deliberately loose - against every visited path, not consumed inputs - because
@@ -356,10 +350,10 @@ def _input_name_was_handled_by_legacy_fallback(input_name: str, handled_inputs:
def test_case_validation(
- test_dict: ToolSourceTest, tool_parameter_bundle: List[ToolParameterT], profile: str, name: Optional[str] = None
+ test_dict: ToolSourceTest, tool_parameter_bundle: list[ToolParameterT], profile: str, name: str | None = None
) -> TestCaseStateValidationResult:
test_case_state_and_warnings = test_case_state(test_dict, tool_parameter_bundle, profile, validate=False)
- exception: Optional[Exception] = None
+ exception: Exception | None = None
try:
test_case_state_and_warnings.tool_state.validate(tool_parameter_bundle, name=name)
for input_name in test_case_state_and_warnings.unhandled_inputs:
@@ -376,20 +370,20 @@ def test_case_validation(
def _merge_level_into_state(
- tool_inputs: List[ToolParameterT],
+ tool_inputs: list[ToolParameterT],
context: MergeContext,
state_at_level: dict,
- prefix: Optional[str],
-) -> Set[str]:
- handled_inputs: Set[str] = set()
+ prefix: str | None,
+) -> set[str]:
+ handled_inputs: set[str] = set()
for tool_input in tool_inputs:
handled_inputs.update(_merge_into_state(tool_input, context, state_at_level, prefix))
return handled_inputs
-def _inputs_as_dict(inputs: ToolSourceTestInputs) -> Dict[str, ToolSourceTestInput]:
- as_dict: Dict[str, ToolSourceTestInput] = {}
+def _inputs_as_dict(inputs: ToolSourceTestInputs) -> dict[str, ToolSourceTestInput]:
+ as_dict: dict[str, ToolSourceTestInput] = {}
for input in inputs:
as_dict[input["name"]] = input
@@ -400,8 +394,8 @@ def _merge_into_state(
tool_input: ToolParameterT,
context: MergeContext,
state_at_level: dict,
- prefix: Optional[str],
-) -> Set[str]:
+ prefix: str | None,
+) -> set[str]:
handled_inputs = set()
input_name = tool_input.name
@@ -466,7 +460,7 @@ def _merge_into_state(
elif isinstance(tool_input, (DataParameterModel,)):
if tool_input.multiple:
value = test_input["value"]
- input_value_list: List[Any] = []
+ input_value_list: list[Any] = []
if value:
if context.state_representation == "test_case_json":
input_value_list = test_input["value"] if test_input["value"] is not None else []
@@ -506,8 +500,8 @@ def _merge_into_state(
def _repeat_inputs_to_array(
- state_path: str, parameters: List[ToolParameterT], inputs: ToolSourceTestInputs
-) -> List[ToolSourceTestInputs]:
+ state_path: str, parameters: list[ToolParameterT], inputs: ToolSourceTestInputs
+) -> list[ToolSourceTestInputs]:
inputs_as_dict = _inputs_as_dict(inputs)
repeat_instance_input_dicts = repeat_inputs_to_array(state_path, inputs_as_dict)
if not repeat_instance_input_dicts and "|" in state_path:
@@ -525,7 +519,7 @@ def _repeat_inputs_to_array(
if repeat_instance_inputs:
return repeat_instance_inputs
- legacy_repeat_inputs: List[ToolSourceTestInputs] = []
+ legacy_repeat_inputs: list[ToolSourceTestInputs] = []
for parameter in parameters:
parameter_name = parameter.name
matching_inputs = [input for input in inputs if input["name"] == parameter_name]
@@ -543,7 +537,7 @@ def _select_which_when(
state: dict,
context: MergeContext,
prefix: str,
-) -> Tuple[ConditionalWhen, Optional[str]]:
+) -> tuple[ConditionalWhen, str | None]:
"""Return the selected when and the name of the test input used as the discriminator
(or ``None`` if the discriminator was omitted). The discriminator name lets callers mark
it consumed so descendant conditionals do not re-match it via the loose fallbacks."""
@@ -572,7 +566,7 @@ def _select_which_when(
raise Exception(f"Invalid conditional test value ({explicit_test_value}) for parameter ({test_parameter_name})")
-def _leaf_param_short_names(parameters: List[ToolParameterT]) -> Set[str]:
+def _leaf_param_short_names(parameters: list[ToolParameterT]) -> set[str]:
"""Collect the leaf parameter short names reachable from a list of parameters,
descending into repeats, sections and nested conditionals (including each
conditional's discriminator)."""
@@ -584,13 +578,13 @@ def _leaf_param_short_names(parameters: List[ToolParameterT]) -> Set[str]:
def _infer_when_from_inputs(
- conditional: ConditionalParameterModel, inputs: ToolSourceTestInputs, prefix: Optional[str]
-) -> Optional[ConditionalWhen]:
+ conditional: ConditionalParameterModel, inputs: ToolSourceTestInputs, prefix: str | None
+) -> ConditionalWhen | None:
"""When a conditional's discriminator is omitted, pick the when whose parameters the
test supplies. Returns the best-matching when only when it is a strictly better match
than the default when; otherwise None so the caller uses the default when."""
scope = f"{prefix}|" if prefix else ""
- provided_short_names: Set[str] = set()
+ provided_short_names: set[str] = set()
for input in inputs:
name = input["name"]
# Consider inputs scoped to this conditional, plus legacy unqualified (bare) inputs -
@@ -603,7 +597,7 @@ def _infer_when_from_inputs(
if not provided_short_names:
return None
- best_when: Optional[ConditionalWhen] = None
+ best_when: ConditionalWhen | None = None
best_score = 0
default_score = 0
for when in conditional.whens:
@@ -619,8 +613,8 @@ def _infer_when_from_inputs(
def _resolve_matching_inputs(
- matching_inputs: List[ToolSourceTestInput], ambiguity_message: str
-) -> Optional[ToolSourceTestInput]:
+ matching_inputs: list[ToolSourceTestInput], ambiguity_message: str
+) -> ToolSourceTestInput | None:
"""Resolve a list of test inputs that matched a parameter to a single input.
Returns None when nothing matched (so the caller can try the next fallback). A single
@@ -650,7 +644,7 @@ def _path_ends_with_param(qualified_path: str, param_name: str) -> bool:
return qualified_path.endswith(f"|{param_name}")
-def _is_conditional_elided_match(input_name: str, path_segments: List[str]) -> bool:
+def _is_conditional_elided_match(input_name: str, path_segments: list[str]) -> bool:
"""True if ``input_name`` is the qualified ``path_segments`` with intermediate
(conditional) segments removed - sharing the head and leaf segments.
@@ -666,8 +660,8 @@ def _is_conditional_elided_match(input_name: str, path_segments: List[str]) -> b
def validate_test_cases_for_tool_source(
- tool_source: ToolSource, use_latest_profile: bool = False, name: Optional[str] = None
-) -> List[TestCaseStateValidationResult]:
+ tool_source: ToolSource, use_latest_profile: bool = False, name: str | None = None
+) -> list[TestCaseStateValidationResult]:
name = name or f"PydanticModelFor[{tool_source.parse_id()}]"
tool_parameter_bundle = input_models_for_tool_source(tool_source)
if use_latest_profile:
@@ -675,8 +669,8 @@ def validate_test_cases_for_tool_source(
profile = "26.1"
else:
profile = tool_source.parse_profile()
- test_cases: List[ToolSourceTest] = tool_source.parse_tests_to_dict()["tests"]
- results_by_test: List[TestCaseStateValidationResult] = []
+ test_cases: list[ToolSourceTest] = tool_source.parse_tests_to_dict()["tests"]
+ results_by_test: list[TestCaseStateValidationResult] = []
for test_case in test_cases:
validation_result = test_case_validation(test_case, tool_parameter_bundle.parameters, profile, name=name)
results_by_test.append(validation_result)
diff --git a/lib/galaxy/tool_util/parameters/convert.py b/lib/galaxy/tool_util/parameters/convert.py
index 4e0a6172caf..90ea7c2840a 100644
--- a/lib/galaxy/tool_util/parameters/convert.py
+++ b/lib/galaxy/tool_util/parameters/convert.py
@@ -1,17 +1,15 @@
"""Utilities for converting between request states."""
import logging
+from collections.abc import (
+ Callable,
+ Sequence,
+)
from copy import deepcopy
from dataclasses import dataclass
from typing import (
Any,
- Callable,
cast,
- Dict,
- List,
- Optional,
- Sequence,
- Union,
)
from galaxy.tool_util_models.parameters import (
@@ -78,7 +76,7 @@ DereferenceCallable = Callable[[DataRequestUri], DataRequestInternalHda]
DereferenceCollectionCallable = Callable[[DataRequestCollectionUri], DataRequestInternalHdca]
# interfaces for adapting test data dictionaries to tool request dictionaries
# e.g. {class: File, path: foo.bed} => {src: hda, id: ab1235cdfea3}
-AdaptDatasets = Callable[[JsonTestDatasetDefDict], Union[DataRequestHda, DataRequestUri]]
+AdaptDatasets = Callable[[JsonTestDatasetDefDict], DataRequestHda | DataRequestUri]
AdaptCollections = Callable[[JsonTestCollectionDefDict], DataCollectionRequest]
OPENAPI_REF_TEMPLATE = "#/components/schemas/{model}"
@@ -92,7 +90,7 @@ class RequestInternalToWorkflowStateError(ValueError):
def cwl_runtime_model(input_models: ToolParameterBundle):
model = create_job_runtime_model(input_models)
- openapi_schema: Dict[str, Any] = {
+ openapi_schema: dict[str, Any] = {
"openapi": "3.1.0",
"info": {
"title": "Custom API",
@@ -112,7 +110,7 @@ def decode(
external_state: RequestToolState,
input_models: ToolParameterBundle,
decode_id: Callable[[str], int],
- name_base: Optional[str] = None,
+ name_base: str | None = None,
) -> RequestInternalToolState:
"""Prepare an internal representation of tool state (request_internal) for storing in the database."""
@@ -184,14 +182,14 @@ def strictify(relaxed_state: RelaxedRequestToolState, input_models: ToolParamete
tool_state = deepcopy(relaxed_state.input_state)
- def _strictify_parameter(tool_state: Dict[str, Any], parameter: ToolParameterT) -> None:
+ def _strictify_parameter(tool_state: dict[str, Any], parameter: ToolParameterT) -> None:
if isinstance(parameter, ConditionalParameterModel):
conditional_state = _initialize_conditional_state(parameter, tool_state)
test_parameter = parameter.test_parameter
test_parameter_name = test_parameter.name
- explicit_test_value: Optional[DiscriminatorType] = (
+ explicit_test_value: DiscriminatorType | None = (
conditional_state[test_parameter_name] if test_parameter_name in conditional_state else None
)
test_value = validate_explicit_conditional_test_value(test_parameter_name, explicit_test_value)
@@ -220,7 +218,7 @@ def strictify(relaxed_state: RelaxedRequestToolState, input_models: ToolParamete
if not parameter.optional and tool_state[parameter_name] is None:
tool_state[parameter_name] = parameter.default_value if parameter.default_value is not None else ""
- def _strictify_parameters(tool_state: Dict[str, Any], input_models: ToolParameterBundle) -> None:
+ def _strictify_parameters(tool_state: dict[str, Any], input_models: ToolParameterBundle) -> None:
for parameter in input_models.parameters:
_strictify_parameter(tool_state, parameter)
@@ -231,7 +229,7 @@ def strictify(relaxed_state: RelaxedRequestToolState, input_models: ToolParamete
return request_state
-def _deferred_url_default_request(url: str) -> Dict[str, Any]:
+def _deferred_url_default_request(url: str) -> dict[str, Any]:
"""Build the deferred dataset request used to materialize a data param's url_default."""
return DataRequestUri(url=url, ext="auto", deferred=True).model_dump()
@@ -356,13 +354,13 @@ class MappedCollectionInput:
src: str
id: int
- map_over_type: Optional[str] = None
+ map_over_type: str | None = None
linked: bool = True
def from_workflow_execution_state(
- resolved_tool_state: Dict[str, Any],
- mapped_inputs: Dict[str, MappedCollectionInput],
+ resolved_tool_state: dict[str, Any],
+ mapped_inputs: dict[str, MappedCollectionInput],
input_models: ToolParameterBundle,
) -> RequestInternalToolState:
"""Synthesize request_internal from a resolved workflow tool-step execution.
@@ -382,7 +380,7 @@ def from_workflow_execution_state(
def batch_for(mapped: MappedCollectionInput) -> dict:
if mapped.linked is False:
raise RequestInternalToWorkflowStateError(CROSS_PRODUCT_MAP_OVER_ERROR_MESSAGE)
- value: Dict[str, Any] = {"src": mapped.src, "id": mapped.id}
+ value: dict[str, Any] = {"src": mapped.src, "id": mapped.id}
if mapped.map_over_type is not None:
value["map_over_type"] = mapped.map_over_type
return {"__class__": "Batch", "values": [value], "linked": mapped.linked}
@@ -419,7 +417,7 @@ def encode_test(
if value is not None:
if parameter.multiple:
assert isinstance(value, list), str(value)
- test_datasets = cast(List[JsonTestDatasetDefDict], value)
+ test_datasets = cast(list[JsonTestDatasetDefDict], value)
return [d.model_dump() for d in map(adapt_datasets, test_datasets)]
else:
assert isinstance(value, dict), str(value)
@@ -461,11 +459,11 @@ def encode_test(
def fill_static_defaults(
- tool_state: Dict[str, Any],
+ tool_state: dict[str, Any],
input_models: ToolParameterBundle,
profile: float,
partial: bool = True,
-) -> Dict[str, Any]:
+) -> dict[str, Any]:
"""Fill static defaults into a job_internal tool state; pass only that representation.
Request/request_internal states record absent inputs as absent - filling them here would
@@ -480,12 +478,12 @@ def fill_static_defaults(
return tool_state
-def _fill_defaults(tool_state: Dict[str, Any], input_models: ToolParameterBundle) -> None:
+def _fill_defaults(tool_state: dict[str, Any], input_models: ToolParameterBundle) -> None:
for parameter in input_models.parameters:
_fill_default_for(tool_state, parameter)
-def _fill_default_for(tool_state: Dict[str, Any], parameter: ToolParameterT) -> None:
+def _fill_default_for(tool_state: dict[str, Any], parameter: ToolParameterT) -> None:
parameter_name = parameter.name
if isinstance(parameter, BooleanParameterModel):
if parameter_name not in tool_state:
@@ -526,7 +524,7 @@ def _fill_default_for(tool_state: Dict[str, Any], parameter: ToolParameterT) ->
test_parameter = parameter.test_parameter
test_parameter_name = test_parameter.name
- explicit_test_value: Optional[DiscriminatorType] = (
+ explicit_test_value: DiscriminatorType | None = (
conditional_state[test_parameter_name] if test_parameter_name in conditional_state else None
)
test_value = validate_explicit_conditional_test_value(test_parameter_name, explicit_test_value)
@@ -559,12 +557,12 @@ def _fill_default_for(tool_state: Dict[str, Any], parameter: ToolParameterT) ->
tool_state[parameter_name] = parameter.default_value if parameter.default_value is not None else ""
-def _fill_url_defaults(tool_state: Dict[str, Any], input_models: ToolParameterBundle) -> None:
+def _fill_url_defaults(tool_state: dict[str, Any], input_models: ToolParameterBundle) -> None:
for parameter in input_models.parameters:
_fill_url_default_for(tool_state, parameter)
-def _fill_url_default_for(tool_state: Dict[str, Any], parameter: ToolParameterT) -> None:
+def _fill_url_default_for(tool_state: dict[str, Any], parameter: ToolParameterT) -> None:
"""Inject deferred ``url_default`` data requests for absent data parameters.
Unlike :func:`_fill_default_for` this materializes *only* ``url_default`` data
@@ -582,7 +580,7 @@ def _fill_url_default_for(tool_state: Dict[str, Any], parameter: ToolParameterT)
raw_state = tool_state.get(parameter_name)
conditional_seed = raw_state if isinstance(raw_state, dict) else {}
test_parameter_name = parameter.test_parameter.name
- explicit_test_value: Optional[DiscriminatorType] = conditional_seed.get(test_parameter_name)
+ explicit_test_value: DiscriminatorType | None = conditional_seed.get(test_parameter_name)
test_value = validate_explicit_conditional_test_value(test_parameter_name, explicit_test_value)
when = _select_which_when(parameter, test_value, conditional_seed)
if not _parameters_have_url_default(when.parameters):
@@ -608,30 +606,30 @@ def _parameters_have_url_default(parameters: Sequence[ToolParameterT]) -> bool:
)
-def _initialize_section_state(parameter: SectionParameterModel, tool_state: Dict[str, Any]) -> Dict[str, Any]:
+def _initialize_section_state(parameter: SectionParameterModel, tool_state: dict[str, Any]) -> dict[str, Any]:
parameter_name = parameter.name
if parameter_name not in tool_state:
tool_state[parameter_name] = {}
- section_state = cast(Dict[str, Any], tool_state[parameter_name])
+ section_state = cast(dict[str, Any], tool_state[parameter_name])
return section_state
-def _initialize_conditional_state(parameter: ConditionalParameterModel, tool_state: Dict[str, Any]) -> Dict[str, Any]:
+def _initialize_conditional_state(parameter: ConditionalParameterModel, tool_state: dict[str, Any]) -> dict[str, Any]:
parameter_name = parameter.name
if parameter_name not in tool_state:
tool_state[parameter_name] = {}
raw_conditional_state = tool_state[parameter_name]
assert isinstance(raw_conditional_state, dict)
- conditional_state = cast(Dict[str, Any], raw_conditional_state)
+ conditional_state = cast(dict[str, Any], raw_conditional_state)
return conditional_state
-def _initialize_repeat_state(parameter: RepeatParameterModel, tool_state: Dict[str, Any]) -> List[Dict[str, Any]]:
+def _initialize_repeat_state(parameter: RepeatParameterModel, tool_state: dict[str, Any]) -> list[dict[str, Any]]:
parameter_name = parameter.name
if parameter_name not in tool_state:
tool_state[parameter_name] = []
- repeat_instances = cast(List[Dict[str, Any]], tool_state[parameter_name])
+ repeat_instances = cast(list[dict[str, Any]], tool_state[parameter_name])
if parameter.min:
while len(repeat_instances) < parameter.min:
repeat_instances.append({})
@@ -639,7 +637,7 @@ def _initialize_repeat_state(parameter: RepeatParameterModel, tool_state: Dict[s
def _select_which_when(
- conditional: ConditionalParameterModel, test_value: Optional[DiscriminatorType], conditional_state: Dict[str, Any]
+ conditional: ConditionalParameterModel, test_value: DiscriminatorType | None, conditional_state: dict[str, Any]
) -> ConditionalWhen:
for when in conditional.whens:
if test_value is None and when.is_default_when:
@@ -731,7 +729,7 @@ def _decode_callback_for(decode_id: DecodeFunctionT) -> Callback:
DatasetToRuntimeJson = Callable[[DataJobInternalT], DataInternalJson]
-CollectionToRuntimeJson = Callable[[DataCollectionRequestInternal, Optional[str]], Any]
+CollectionToRuntimeJson = Callable[[DataCollectionRequestInternal, str | None], Any]
# Parameter models the narrow YAML authoring layer is allowed to produce.
diff --git a/lib/galaxy/tool_util/parameters/factory.py b/lib/galaxy/tool_util/parameters/factory.py
index 1eb81f4bbdc..22abce4a868 100644
--- a/lib/galaxy/tool_util/parameters/factory.py
+++ b/lib/galaxy/tool_util/parameters/factory.py
@@ -1,11 +1,7 @@
from typing import (
Any,
cast,
- Dict,
- List,
- Optional,
TYPE_CHECKING,
- Union,
)
from typing_extensions import TypedDict
@@ -86,11 +82,9 @@ class _CommonParamKwargs(TypedDict, total=False):
def _common_param_kwargs(input_source: InputSource) -> _CommonParamKwargs:
"""Extract common metadata (label, help) from InputSource for parameter models."""
kwargs = _CommonParamKwargs()
- label = input_source.parse_label()
- if label:
+ if label := input_source.parse_label():
kwargs["label"] = label
- help_text = input_source.parse_help()
- if help_text:
+ if help_text := input_source.parse_help():
kwargs["help"] = help_text
return kwargs
@@ -102,7 +96,7 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool
if param_type == "integer":
optional = input_source.parse_optional()
value = input_source.get("value")
- int_value: Optional[int]
+ int_value: int | None
if value:
int_value = int(value)
elif optional:
@@ -113,7 +107,7 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool
else:
raise ParameterDefinitionError()
static_validator_models = static_validators(input_source.parse_validators())
- int_validators: List[NumberCompatiableValidators] = []
+ int_validators: list[NumberCompatiableValidators] = []
for static_validator in static_validator_models:
if static_validator.type == "in_range":
int_validators.append(static_validator)
@@ -149,7 +143,7 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool
optional, optionality_inferred = text_input_is_optional(input_source)
implicit_default = None if optional else ""
default_value = input_source.get("value", implicit_default)
- text_validators: List[TextCompatiableValidators] = _text_validators(input_source)
+ text_validators: list[TextCompatiableValidators] = _text_validators(input_source)
return TextParameterModel(
type="text",
name=input_source.parse_name(),
@@ -161,7 +155,7 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool
elif param_type == "float":
optional = input_source.parse_optional()
value = input_source.get("value")
- float_value: Optional[float]
+ float_value: float | None
if value:
float_value = float(value)
elif optional:
@@ -172,7 +166,7 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool
else:
raise ParameterDefinitionError()
static_validator_models = static_validators(input_source.parse_validators())
- float_validators: List[NumberCompatiableValidators] = []
+ float_validators: list[NumberCompatiableValidators] = []
for static_validator in static_validator_models:
if static_validator.type == "in_range":
float_validators.append(static_validator)
@@ -193,7 +187,7 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool
elif param_type == "hidden":
optional = input_source.parse_optional()
value = input_source.get("value")
- hidden_validators: List[TextCompatiableValidators] = _text_validators(input_source)
+ hidden_validators: list[TextCompatiableValidators] = _text_validators(input_source)
return HiddenParameterModel(
type="hidden",
name=input_source.parse_name(),
@@ -251,13 +245,13 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool
dynamic_options_config = input_source.parse_dynamic_options()
is_static = dynamic_options_config is None
multiple = input_source.get_bool("multiple", False)
- options: Optional[List[LabelValue]] = None
+ options: list[LabelValue] | None = None
if is_static:
options = []
for option_label, option_value, selected in input_source.parse_static_options():
options.append(LabelValue(label=option_label, value=option_value, selected=selected))
static_validator_models = static_validators(input_source.parse_validators())
- select_validators: List[SelectCompatiableValidators] = []
+ select_validators: list[SelectCompatiableValidators] = []
for static_validator in static_validator_models:
if static_validator.type == "no_options":
# test case test_tool_execute::test_select_optional_null_by_default verifies
@@ -339,7 +333,7 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool
**_common_param_kwargs(input_source),
)
elif param_type == "directory_uri":
- directory_uri_validators: List[TextCompatiableValidators] = _text_validators(input_source)
+ directory_uri_validators: list[TextCompatiableValidators] = _text_validators(input_source)
return DirectoryUriParameterModel(
type="directory",
name=input_source.parse_name(),
@@ -351,7 +345,7 @@ def _from_input_source_galaxy(input_source: InputSource, profile: float) -> Tool
elif input_type == "conditional":
test_param_input_source = input_source.parse_test_input_source()
test_parameter = cast(
- Union[BooleanParameterModel, SelectParameterModel],
+ BooleanParameterModel | SelectParameterModel,
_from_input_source_galaxy(test_param_input_source, profile),
)
whens = []
@@ -452,9 +446,9 @@ def _simple_cwl_type_to_model(simple_type: str, input_source: "CwlInputSource"):
)
-def _text_validators(input_source: InputSource) -> List[TextCompatiableValidators]:
+def _text_validators(input_source: InputSource) -> list[TextCompatiableValidators]:
static_validator_models = static_validators(input_source.parse_validators())
- text_validators: List[TextCompatiableValidators] = []
+ text_validators: list[TextCompatiableValidators] = []
for static_validator in static_validator_models:
if static_validator.type == "length":
text_validators.append(static_validator)
@@ -485,11 +479,11 @@ def _from_input_source_cwl(input_source: "CwlInputSource") -> ToolParameterT:
raise NotImplementedError("Cannot generate tool parameter model for this CWL artifact yet.")
-def input_models_from_json(json: List[Dict[str, Any]]) -> ToolParameterBundle:
+def input_models_from_json(json: list[dict[str, Any]]) -> ToolParameterBundle:
return ToolParameterBundleModel(parameters=json)
-def tool_parameter_bundle_from_json(json: Dict[str, Any]) -> ToolParameterBundleModel:
+def tool_parameter_bundle_from_json(json: dict[str, Any]) -> ToolParameterBundleModel:
return ToolParameterBundleModel(**json)
@@ -499,7 +493,7 @@ def input_models_for_tool_source(tool_source: ToolSource) -> ToolParameterBundle
return ToolParameterBundleModel(parameters=input_models_for_pages(pages, profile))
-def input_models_for_pages(pages: PagesSource, profile: float) -> List[ToolParameterT]:
+def input_models_for_pages(pages: PagesSource, profile: float) -> list[ToolParameterT]:
input_models = []
if pages.inputs_style != "none":
for page_source in pages.page_sources:
@@ -508,7 +502,7 @@ def input_models_for_pages(pages: PagesSource, profile: float) -> List[ToolParam
return input_models
-def input_models_for_page(page_source: PageSource, profile: float) -> List[ToolParameterT]:
+def input_models_for_page(page_source: PageSource, profile: float) -> list[ToolParameterT]:
input_models = []
for input_source in page_source.parse_input_sources():
input_type = input_source.parse_input_type()
diff --git a/lib/galaxy/tool_util/parameters/json.py b/lib/galaxy/tool_util/parameters/json.py
index 9675acee40e..b723934c1e9 100644
--- a/lib/galaxy/tool_util/parameters/json.py
+++ b/lib/galaxy/tool_util/parameters/json.py
@@ -2,12 +2,10 @@ import json
import re
from typing import (
Any,
- Dict,
- List,
+ Literal,
)
from pydantic.json_schema import GenerateJsonSchema
-from typing_extensions import Literal
MODE = Literal["validation", "serialization"]
DEFAULT_JSON_SCHEMA_MODE: MODE = "validation"
@@ -16,16 +14,15 @@ WHEN_ABSENT_RE = re.compile(r"^When_(.+)___absent$")
class CustomGenerateJsonSchema(GenerateJsonSchema):
-
def generate(self, schema, mode: MODE = DEFAULT_JSON_SCHEMA_MODE):
json_schema = super().generate(schema, mode=mode)
json_schema["$schema"] = self.schema_dialect
return json_schema
-def _absent_test_params(defs: Dict[str, Any]) -> Dict[str, str]:
+def _absent_test_params(defs: dict[str, Any]) -> dict[str, str]:
"""Map test parameter names to their absent branch def names, longest name first."""
- result: Dict[str, str] = {}
+ result: dict[str, str] = {}
for def_name in defs:
m = WHEN_ABSENT_RE.match(def_name)
if m:
@@ -33,7 +30,7 @@ def _absent_test_params(defs: Dict[str, Any]) -> Dict[str, str]:
return dict(sorted(result.items(), key=lambda item: len(item[0]), reverse=True))
-def _match_when_branch(def_name: str, absent_test_params: Dict[str, str]) -> Any:
+def _match_when_branch(def_name: str, absent_test_params: dict[str, str]) -> Any:
"""Return (test_param_name, value_suffix) for an explicit When branch, or None."""
if not def_name.startswith("When_") or "___absent" in def_name:
return None
@@ -44,7 +41,7 @@ def _match_when_branch(def_name: str, absent_test_params: Dict[str, str]) -> Any
return None
-def _fix_conditional_oneofs(schema: Dict[str, Any]) -> None:
+def _fix_conditional_oneofs(schema: dict[str, Any]) -> None:
"""Make conditional discriminated unions unambiguous for JSON Schema validators.
Pydantic uses a custom callable discriminator for conditionals that doesn't
@@ -69,18 +66,18 @@ def _fix_conditional_oneofs(schema: Dict[str, Any]) -> None:
_make_field_required(def_schema, match[0])
-def _make_field_required(def_schema: Dict[str, Any], field_name: str) -> None:
+def _make_field_required(def_schema: dict[str, Any], field_name: str) -> None:
props = def_schema.get("properties", {})
if field_name not in props:
return
- required: List[str] = def_schema.get("required", [])
+ required: list[str] = def_schema.get("required", [])
if field_name not in required:
required.append(field_name)
def_schema["required"] = required
props[field_name].pop("default", None)
-def _discriminator_key(def_schema: Dict[str, Any], test_param_name: str, value_suffix: str) -> str:
+def _discriminator_key(def_schema: dict[str, Any], test_param_name: str, value_suffix: str) -> str:
"""Derive the discriminator mapping key from the branch's const value.
Uses the actual ``const`` value from the schema property so boolean branches
@@ -88,13 +85,12 @@ def _discriminator_key(def_schema: Dict[str, Any], test_param_name: str, value_s
"""
props = def_schema.get("properties", {})
test_prop = props.get(test_param_name, {})
- const = test_prop.get("const")
- if const is not None:
+ if (const := test_prop.get("const")) is not None:
return json.dumps(const) if isinstance(const, bool) else str(const)
return value_suffix
-def _add_conditional_discriminators(schema: Dict[str, Any]) -> None:
+def _add_conditional_discriminators(schema: dict[str, Any]) -> None:
"""Add OpenAPI 3.1 discriminator objects and human-readable titles to conditional oneOfs."""
defs = schema.get("$defs", {})
if not defs:
@@ -124,7 +120,7 @@ def _add_conditional_discriminators(schema: Dict[str, Any]) -> None:
if test_param_name is None:
continue
- mapping: Dict[str, str] = {}
+ mapping: dict[str, str] = {}
for branch in one_of:
ref = branch.get("$ref", "")
branch_def_name = ref.rsplit("/", 1)[-1] if "/" in ref else ""
@@ -141,7 +137,7 @@ def _add_conditional_discriminators(schema: Dict[str, Any]) -> None:
}
-def _conditional_test_param_for_oneof(one_of: List[Any], absent_test_params: Dict[str, str]) -> Any:
+def _conditional_test_param_for_oneof(one_of: list[Any], absent_test_params: dict[str, str]) -> Any:
"""Return the test parameter name if this oneOf is a conditional discriminated union."""
for branch in one_of:
ref = branch.get("$ref", "")
@@ -155,7 +151,7 @@ def _conditional_test_param_for_oneof(one_of: List[Any], absent_test_params: Dic
COLLECTION_RUNTIME_NESTED_DEFS = frozenset(["DataCollectionNestedListRuntime", "DataCollectionNestedRecordRuntime"])
-def _fix_collection_runtime_oneofs(schema: Dict[str, Any]) -> None:
+def _fix_collection_runtime_oneofs(schema: dict[str, Any]) -> None:
"""Convert collection runtime oneOf to anyOf to avoid discriminator overlap.
The Pydantic callable discriminator routes by collection_type pattern but
@@ -183,7 +179,7 @@ def _walk_and_fix_collection_oneofs(node: Any) -> None:
_walk_and_fix_collection_oneofs(value)
-def _is_collection_runtime_oneof(branches: List[Any]) -> bool:
+def _is_collection_runtime_oneof(branches: list[Any]) -> bool:
for branch in branches:
ref = branch.get("$ref", "")
def_name = ref.rsplit("/", 1)[-1] if "/" in ref else ""
@@ -200,7 +196,7 @@ _ANNOTATED_TYPES_TO_JSON_SCHEMA = {
}
-def _normalize_annotated_types_keywords(schema: Dict[str, Any]) -> None:
+def _normalize_annotated_types_keywords(schema: dict[str, Any]) -> None:
"""Convert annotated_types constraint keys to standard JSON Schema keywords.
When annotated_types constraints (Ge, Gt, Le, Lt) are applied to Union types,
@@ -225,7 +221,7 @@ def _walk_and_normalize(node: Any) -> None:
_walk_and_normalize(value)
-def to_json_schema(model, mode: MODE = DEFAULT_JSON_SCHEMA_MODE) -> Dict[str, Any]:
+def to_json_schema(model, mode: MODE = DEFAULT_JSON_SCHEMA_MODE) -> dict[str, Any]:
schema = model.model_json_schema(schema_generator=CustomGenerateJsonSchema, mode=mode)
_fix_conditional_oneofs(schema)
_add_conditional_discriminators(schema)
diff --git a/lib/galaxy/tool_util/parameters/model_validation.py b/lib/galaxy/tool_util/parameters/model_validation.py
index f92c459026f..843f5fc43cf 100644
--- a/lib/galaxy/tool_util/parameters/model_validation.py
+++ b/lib/galaxy/tool_util/parameters/model_validation.py
@@ -1,8 +1,5 @@
from typing import (
Any,
- Dict,
- Optional,
- Type,
)
from pydantic import (
@@ -23,7 +20,7 @@ from galaxy.tool_util_models.parameters import (
)
-def validate_against_model(pydantic_model: Type[BaseModel], parameter_state: Dict[str, Any]) -> None:
+def validate_against_model(pydantic_model: type[BaseModel], parameter_state: dict[str, Any]) -> None:
try:
pydantic_model(**parameter_state)
except ValidationError as e:
@@ -33,13 +30,12 @@ def validate_against_model(pydantic_model: Type[BaseModel], parameter_state: Dic
class ValidationFunctionT(Protocol):
-
- def __call__(self, tool: ToolParameterBundle, request: RawStateDict, name: Optional[str] = None) -> None: ...
+ def __call__(self, tool: ToolParameterBundle, request: RawStateDict, name: str | None = None) -> None: ...
def validate_model_type_factory(state_representation: StateRepresentationT) -> ValidationFunctionT:
- def validate_request(tool: ToolParameterBundle, request: Dict[str, Any], name: Optional[str] = None) -> None:
+ def validate_request(tool: ToolParameterBundle, request: dict[str, Any], name: str | None = None) -> None:
name = name or DEFAULT_MODEL_NAME
pydantic_model = create_field_model(tool.parameters, name=name, state_representation=state_representation)
validate_against_model(pydantic_model, request)
diff --git a/lib/galaxy/tool_util/parameters/request.py b/lib/galaxy/tool_util/parameters/request.py
index cd6077f2abb..96c2ee9e979 100644
--- a/lib/galaxy/tool_util/parameters/request.py
+++ b/lib/galaxy/tool_util/parameters/request.py
@@ -2,12 +2,8 @@
from typing import (
Any,
- Dict,
- List,
Literal,
NamedTuple,
- Optional,
- Set,
)
from boltons.iterutils import remap
@@ -25,10 +21,10 @@ class RequestInputRef(NamedTuple):
class RequestUrlInputRef(NamedTuple):
input_name: str
url: str
- request: Dict[str, Any]
+ request: dict[str, Any]
-_SRC_TO_CONTENT_TYPE: Dict[str, RequestInputContentType] = {
+_SRC_TO_CONTENT_TYPE: dict[str, RequestInputContentType] = {
"hda": "dataset",
"hdca": "collection",
"dce": "dataset_collection_element",
@@ -37,15 +33,15 @@ _SRC_TO_CONTENT_TYPE: Dict[str, RequestInputContentType] = {
def request_internal_input_refs(
payload: dict,
- allowed_srcs: Optional[Set[str]] = None,
-) -> List[RequestInputRef]:
+ allowed_srcs: set[str] | None = None,
+) -> list[RequestInputRef]:
"""Walk a request_internal payload and return declared data refs.
The walk intentionally follows the same ``remap`` idiom used by job
request handling: when visiting an ``id`` leaf, inspect the sibling ``src``
value on the parent container to decide whether the value is a data ref.
"""
- refs: List[RequestInputRef] = []
+ refs: list[RequestInputRef] = []
def visit(path, key, value):
if key == "id" and isinstance(value, int) and not isinstance(value, bool):
@@ -64,9 +60,9 @@ def request_internal_input_refs(
return refs
-def request_internal_url_inputs(payload: dict) -> List[RequestUrlInputRef]:
+def request_internal_url_inputs(payload: dict) -> list[RequestUrlInputRef]:
"""Walk a request_internal payload and return declared URL inputs."""
- refs: List[RequestUrlInputRef] = []
+ refs: list[RequestUrlInputRef] = []
def visit(path, key, value):
if key == "url" and isinstance(value, str):
@@ -83,7 +79,7 @@ def request_internal_url_inputs(payload: dict) -> List[RequestUrlInputRef]:
def _input_name_from_request_path(path) -> str:
"""Convert a request payload path to a workflow input connection name."""
- parts: List[str] = []
+ parts: list[str] = []
i = 0
while i < len(path):
segment = path[i]
diff --git a/lib/galaxy/tool_util/parameters/scripts/validate_test_cases.py b/lib/galaxy/tool_util/parameters/scripts/validate_test_cases.py
index 958135f5331..48dd4b05263 100644
--- a/lib/galaxy/tool_util/parameters/scripts/validate_test_cases.py
+++ b/lib/galaxy/tool_util/parameters/scripts/validate_test_cases.py
@@ -4,10 +4,6 @@ import os
import sys
from dataclasses import dataclass
from pathlib import Path
-from typing import (
- List,
- Optional,
-)
from galaxy.tool_util.parameters.case import (
TestCaseStateValidationResult,
@@ -51,11 +47,11 @@ def arg_parser() -> argparse.ArgumentParser:
@dataclass
class ToolTestValidationResults:
tool_id: str
- tool_version: Optional[str]
+ tool_version: str | None
tool_profile: str
tool_path: str
- results: List[TestCaseStateValidationResult]
- load_error: Optional[Exception]
+ results: list[TestCaseStateValidationResult]
+ load_error: Exception | None
def to_dict(self):
return {
@@ -96,7 +92,7 @@ def validate_tool(tool_path, latest) -> ToolTestValidationResults:
tool_id = tool_source.parse_id()
if tool_id is None:
raise NotValidToolException()
- load_error: Optional[Exception] = None
+ load_error: Exception | None = None
try:
results = validate_test_cases_for_tool_source(tool_source, use_latest_profile=latest)
except Exception as e:
diff --git a/lib/galaxy/tool_util/parameters/state.py b/lib/galaxy/tool_util/parameters/state.py
index 9e0fd452ade..513d458d2db 100644
--- a/lib/galaxy/tool_util/parameters/state.py
+++ b/lib/galaxy/tool_util/parameters/state.py
@@ -4,15 +4,10 @@ from abc import (
)
from typing import (
Any,
- Dict,
- List,
- Optional,
- Type,
- Union,
+ Literal,
)
from pydantic import BaseModel
-from typing_extensions import Literal
from galaxy.tool_util_models.parameters import (
create_job_internal_model,
@@ -36,19 +31,19 @@ from .model_validation import (
validate_against_model,
)
-HasToolParameters = Union[List[ToolParameterT], ToolParameterBundle]
+HasToolParameters = list[ToolParameterT] | ToolParameterBundle
class ToolState(ABC):
- input_state: Dict[str, Any]
+ input_state: dict[str, Any]
- def __init__(self, input_state: Dict[str, Any]):
+ def __init__(self, input_state: dict[str, Any]):
self.input_state = input_state
- def _validate(self, pydantic_model: Type[BaseModel]) -> None:
+ def _validate(self, pydantic_model: type[BaseModel]) -> None:
validate_against_model(pydantic_model, self.input_state)
- def validate(self, parameters: HasToolParameters, name: Optional[str] = None) -> None:
+ def validate(self, parameters: HasToolParameters, name: str | None = None) -> None:
base_model = self.parameter_model_for(parameters, name=name)
if base_model is None:
raise NotImplementedError(
@@ -62,7 +57,7 @@ class ToolState(ABC):
"""Get state representation of the inputs."""
@classmethod
- def parameter_model_for(cls, parameters: HasToolParameters, name: Optional[str] = None) -> Type[BaseModel]:
+ def parameter_model_for(cls, parameters: HasToolParameters, name: str | None = None) -> type[BaseModel]:
bundle: ToolParameterBundle
if isinstance(parameters, list):
bundle = ToolParameterBundleModel(parameters=parameters)
@@ -72,7 +67,7 @@ class ToolState(ABC):
@classmethod
@abstractmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
"""Return a model type for this tool state kind."""
@@ -80,7 +75,7 @@ class RelaxedRequestToolState(ToolState):
state_representation: Literal["relaxed_request"] = "relaxed_request"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_relaxed_request_model(parameters, name)
@@ -88,7 +83,7 @@ class RequestToolState(ToolState):
state_representation: Literal["request"] = "request"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_request_model(parameters, name)
@@ -96,7 +91,7 @@ class RequestInternalToolState(ToolState):
state_representation: Literal["request_internal"] = "request_internal"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_request_internal_model(parameters, name)
@@ -104,7 +99,7 @@ class LandingRequestToolState(ToolState):
state_representation: Literal["landing_request"] = "landing_request"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_landing_request_model(parameters, name)
@@ -112,7 +107,7 @@ class LandingRequestInternalToolState(ToolState):
state_representation: Literal["landing_request_internal"] = "landing_request_internal"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_landing_request_internal_model(parameters, name)
@@ -120,7 +115,7 @@ class RequestInternalDereferencedToolState(ToolState):
state_representation: Literal["request_internal_dereferenced"] = "request_internal_dereferenced"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_request_internal_dereferenced_model(parameters, name)
@@ -128,7 +123,7 @@ class JobInternalToolState(ToolState):
state_representation: Literal["job_internal"] = "job_internal"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_job_internal_model(parameters, name)
@@ -136,7 +131,7 @@ class JobRuntimeToolState(ToolState):
state_representation: Literal["job_runtime"] = "job_runtime"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_job_runtime_model(parameters, name)
@@ -144,7 +139,7 @@ class TestCaseToolState(ToolState):
state_representation: Literal["test_case_xml"] = "test_case_xml"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_test_case_model(parameters, name)
@@ -152,7 +147,7 @@ class TestCaseJsonToolState(ToolState):
state_representation: Literal["test_case_json"] = "test_case_json"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_test_case_json_model(parameters, name)
@@ -160,7 +155,7 @@ class WorkflowStepToolState(ToolState):
state_representation: Literal["workflow_step"] = "workflow_step"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_workflow_step_model(parameters, name)
@@ -168,5 +163,5 @@ class WorkflowStepLinkedToolState(ToolState):
state_representation: Literal["workflow_step_linked"] = "workflow_step_linked"
@classmethod
- def _parameter_model_for(cls, parameters: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def _parameter_model_for(cls, parameters: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_workflow_step_linked_model(parameters, name)
diff --git a/lib/galaxy/tool_util/parameters/visitor.py b/lib/galaxy/tool_util/parameters/visitor.py
index ebd515496ad..c60fb5d0ec4 100644
--- a/lib/galaxy/tool_util/parameters/visitor.py
+++ b/lib/galaxy/tool_util/parameters/visitor.py
@@ -1,12 +1,8 @@
+from collections.abc import Iterable
from typing import (
Any,
cast,
- Dict,
- Iterable,
- List,
- Optional,
TypeVar,
- Union,
)
from typing_extensions import Protocol
@@ -43,7 +39,7 @@ def visit_input_values(
tool_state: ToolState,
callback: Callback,
no_replacement_value=VISITOR_NO_REPLACEMENT,
-) -> Dict[str, Any]:
+) -> dict[str, Any]:
return _visit_input_values(
simple_input_models(input_models.parameters),
tool_state.input_state,
@@ -54,22 +50,21 @@ def visit_input_values(
def _visit_input_values(
input_models: Iterable[ToolParameterT],
- input_values: Dict[str, Any],
+ input_values: dict[str, Any],
callback: Callback,
no_replacement_value=VISITOR_NO_REPLACEMENT,
-) -> Dict[str, Any]:
+) -> dict[str, Any]:
- def _callback(name: str, old_values: Dict[str, Any], new_values: Dict[str, Any]):
+ def _callback(name: str, old_values: dict[str, Any], new_values: dict[str, Any]):
input_value = old_values.get(name, VISITOR_UNDEFINED)
if input_value is VISITOR_UNDEFINED:
return
- replacement = callback(model, input_value)
- if replacement != no_replacement_value:
+ if (replacement := callback(model, input_value)) != no_replacement_value:
new_values[name] = replacement
else:
new_values[name] = input_value
- new_input_values: Dict[str, Any] = {}
+ new_input_values: dict[str, Any] = {}
for model in input_models:
name = model.name
input_value = input_values.get(name, VISITOR_UNDEFINED)
@@ -125,7 +120,7 @@ def _select_which_when(conditional: ConditionalParameterModel, state: dict) -> C
raise Exception(f"Invalid conditional test value ({explicit_test_value}) for parameter ({test_parameter_name})")
-def flat_state_path(has_name: Union[str, ToolParameterT], prefix: Optional[str] = None) -> str:
+def flat_state_path(has_name: str | ToolParameterT, prefix: str | None = None) -> str:
"""Given a parameter name or model and an optional prefix, give 'flat' name for parameter in tree."""
if hasattr(has_name, "name"):
name = cast(ToolParameterT, has_name).name
@@ -137,15 +132,15 @@ def flat_state_path(has_name: Union[str, ToolParameterT], prefix: Optional[str]
KVT = TypeVar("KVT")
-def keys_starting_with(flat_tree: Dict[str, KVT], flat_state_path: str) -> Dict[str, KVT]:
- subset: Dict[str, KVT] = {}
+def keys_starting_with(flat_tree: dict[str, KVT], flat_state_path: str) -> dict[str, KVT]:
+ subset: dict[str, KVT] = {}
for key, value in flat_tree.items():
if key.startswith(flat_state_path):
subset[key] = value
return subset
-def repeat_inputs_to_array(flat_state_path: str, inputs: Dict[str, KVT]) -> List[Dict[str, KVT]]:
+def repeat_inputs_to_array(flat_state_path: str, inputs: dict[str, KVT]) -> list[dict[str, KVT]]:
repeat_inputs = keys_starting_with(inputs, flat_state_path + "_")
highest_count = -1
for key in repeat_inputs.keys():
@@ -157,9 +152,9 @@ def repeat_inputs_to_array(flat_state_path: str, inputs: Dict[str, KVT]) -> List
except ValueError:
continue
- params: List[Dict[str, KVT]] = []
+ params: list[dict[str, KVT]] = []
for _ in range(highest_count + 1):
- instance_params: Dict[str, KVT] = {}
+ instance_params: dict[str, KVT] = {}
params.append(instance_params)
for key, value in repeat_inputs.items():
repeat_num_str = key[len(flat_state_path) + 1 :].split("|")[0]
@@ -171,7 +166,7 @@ def repeat_inputs_to_array(flat_state_path: str, inputs: Dict[str, KVT]) -> List
return params
-def validate_explicit_conditional_test_value(test_parameter_name: str, value: Any) -> Optional[Union[str, bool]]:
+def validate_explicit_conditional_test_value(test_parameter_name: str, value: Any) -> str | bool | None:
if value is not None and not isinstance(value, (str, bool)):
raise Exception(f"Invalid conditional test value ({value}) for parameter ({test_parameter_name})")
return value
diff --git a/lib/galaxy/tool_util/parser/cwl.py b/lib/galaxy/tool_util/parser/cwl.py
index daf90631f5a..63a7a607e74 100644
--- a/lib/galaxy/tool_util/parser/cwl.py
+++ b/lib/galaxy/tool_util/parser/cwl.py
@@ -42,7 +42,7 @@ class CwlToolSource(ToolSource):
def __init__(
self,
- tool_file: Optional[str] = None,
+ tool_file: str | None = None,
strict_cwl_validation: bool = True,
tool_proxy: Optional["ToolProxy"] = None,
):
@@ -95,8 +95,7 @@ class CwlToolSource(ToolSource):
return []
def parse_help(self):
- doc = self.tool_proxy.doc()
- if doc:
+ if doc := self.tool_proxy.doc():
return HelpContent(format="plain_text", content=doc)
else:
return None
@@ -129,7 +128,7 @@ class CwlToolSource(ToolSource):
def parse_description(self):
return self.tool_proxy.description()
- def parse_icon(self) -> Optional[str]:
+ def parse_icon(self) -> str | None:
return None # Not implemented
def parse_interactivetool(self):
@@ -139,7 +138,7 @@ class CwlToolSource(ToolSource):
page_source = CwlPageSource(self.tool_proxy)
return PagesSource([page_source])
- def parse_outputs(self, app: Optional[ToolOutputActionApp]):
+ def parse_outputs(self, app: ToolOutputActionApp | None):
output_instances = self.tool_proxy.output_instances()
outputs = {}
output_defs = []
@@ -150,7 +149,7 @@ class CwlToolSource(ToolSource):
outputs[output_def.name] = output_def
return outputs, {}
- def _parse_output(self, app: Optional[ToolOutputActionApp], output_instance: "OutputInstance"):
+ def _parse_output(self, app: ToolOutputActionApp | None, output_instance: "OutputInstance"):
name = output_instance.name
# TODO: handle filters, actions, change_format
output = ToolOutput(name)
@@ -173,8 +172,7 @@ class CwlToolSource(ToolSource):
def parse_requirements(self):
containers = []
- docker_identifier = self.tool_proxy.docker_identifier()
- if docker_identifier:
+ if docker_identifier := self.tool_proxy.docker_identifier():
containers.append({"type": "docker", "identifier": docker_identifier})
software_requirements = self.tool_proxy.software_requirements()
diff --git a/lib/galaxy/tool_util/parser/factory.py b/lib/galaxy/tool_util/parser/factory.py
index 3379d7dfca6..751c72f490d 100644
--- a/lib/galaxy/tool_util/parser/factory.py
+++ b/lib/galaxy/tool_util/parser/factory.py
@@ -1,12 +1,7 @@
"""Constructors for concrete tool and input source objects."""
import logging
-from typing import (
- Callable,
- Dict,
- List,
- Optional,
-)
+from collections.abc import Callable
from yaml import safe_load
@@ -57,7 +52,7 @@ def build_yaml_tool_source(yaml_string: str) -> YamlToolSource:
return YamlToolSource(safe_load(yaml_string))
-TOOL_SOURCE_FACTORIES: Dict[str, Callable[[str], ToolSource]] = {
+TOOL_SOURCE_FACTORIES: dict[str, Callable[[str], ToolSource]] = {
"XmlToolSource": build_xml_tool_source,
"YamlToolSource": build_yaml_tool_source,
"CwlToolSource": build_cwl_tool_source,
@@ -65,13 +60,13 @@ TOOL_SOURCE_FACTORIES: Dict[str, Callable[[str], ToolSource]] = {
def get_tool_source(
- config_file: Optional[StrPath] = None,
- xml_tree: Optional[ElementTree] = None,
+ config_file: StrPath | None = None,
+ xml_tree: ElementTree | None = None,
enable_beta_formats: bool = True,
- tool_location_fetcher: Optional[ToolLocationFetcher] = None,
- macro_paths: Optional[List[str]] = None,
- tool_source_class: Optional[str] = None,
- raw_tool_source: Optional[str] = None,
+ tool_location_fetcher: ToolLocationFetcher | None = None,
+ macro_paths: list[str] | None = None,
+ tool_source_class: str | None = None,
+ raw_tool_source: str | None = None,
) -> ToolSource:
"""Return a ToolSource object corresponding to supplied source.
diff --git a/lib/galaxy/tool_util/parser/interface.py b/lib/galaxy/tool_util/parser/interface.py
index 49d82bbcb43..e7b2f5ce007 100644
--- a/lib/galaxy/tool_util/parser/interface.py
+++ b/lib/galaxy/tool_util/parser/interface.py
@@ -5,22 +5,19 @@ from abc import (
ABCMeta,
abstractmethod,
)
+from collections.abc import Sequence
from os.path import join
from typing import (
Any,
cast,
- Dict,
- List,
+ Literal,
Optional,
- Sequence,
- Tuple,
TYPE_CHECKING,
Union,
)
import packaging.version
from typing_extensions import (
- Literal,
NotRequired,
TypedDict,
)
@@ -70,74 +67,74 @@ NOT_IMPLEMENTED_MESSAGE = "Galaxy tool format does not yet support this tool fea
INPUT_CLASS_T = Literal["galaxy", "cwl"]
-XmlInt = Union[str, int]
+XmlInt = str | int
class ToolSourceTestOutputAttributes(TypedDict):
- object: NotRequired[Optional[Any]]
+ object: NotRequired[Any | None]
compare: OutputCompareType
lines_diff: int
delta: int
- delta_frac: Optional[float]
+ delta_frac: float | None
sort: bool
decompress: bool
- location: NotRequired[Optional[str]]
- ftype: NotRequired[Optional[str]]
+ location: NotRequired[str | None]
+ ftype: NotRequired[str | None]
eps: float
metric: str
- pin_labels: Optional[Any]
- count: Optional[int]
- min: Optional[int]
- max: Optional[int]
- metadata: Dict[str, Any]
- md5: Optional[str]
- checksum: Optional[str]
- primary_datasets: Dict[str, Any]
- elements: Dict[str, Any]
+ pin_labels: Any | None
+ count: int | None
+ min: int | None
+ max: int | None
+ metadata: dict[str, Any]
+ md5: str | None
+ checksum: str | None
+ primary_datasets: dict[str, Any]
+ elements: dict[str, Any]
assert_list: AssertionList
- extra_files: List[Dict[str, Any]]
+ extra_files: list[dict[str, Any]]
class ToolSourceTestOutput(TypedDict):
name: str
- value: Optional[str]
+ value: str | None
attributes: ToolSourceTestOutputAttributes
# The unfortunate 'attrib = dict(param_elem.attrib)' makes this difficult to type.
-ToolSourceTestInputAttributes = Dict[str, Any]
+ToolSourceTestInputAttributes = dict[str, Any]
class ToolSourceTestInput(TypedDict):
name: str
- value: Optional[Any]
+ value: Any | None
attributes: ToolSourceTestInputAttributes
-ToolSourceTestInputs = List[ToolSourceTestInput]
-ToolSourceTestOutputs = List[ToolSourceTestOutput]
+ToolSourceTestInputs = list[ToolSourceTestInput]
+ToolSourceTestOutputs = list[ToolSourceTestOutput]
TestSourceTestOutputColllection = Any
class ToolSourceTest(TypedDict):
inputs: ToolSourceTestInputs
outputs: ToolSourceTestOutputs
- output_collections: List[TestSourceTestOutputColllection]
+ output_collections: list[TestSourceTestOutputColllection]
stdout: AssertionList
stderr: AssertionList
- expect_exit_code: Optional[XmlInt]
+ expect_exit_code: XmlInt | None
expect_failure: bool
expect_test_failure: bool
- maxseconds: Optional[XmlInt]
- expect_num_outputs: Optional[XmlInt]
+ maxseconds: XmlInt | None
+ expect_num_outputs: XmlInt | None
command: AssertionList
command_version: AssertionList
value_state_representation: Literal["test_case_xml", "test_case_json"]
- credentials: Optional[List[DirectCredential]]
+ credentials: list[DirectCredential] | None
class ToolSourceTests(TypedDict):
- tests: List[ToolSourceTest]
+ tests: list[ToolSourceTest]
class ToolSource(metaclass=ABCMeta):
@@ -148,21 +145,21 @@ class ToolSource(metaclass=ABCMeta):
language: str
@abstractmethod
- def parse_id(self) -> Optional[str]:
+ def parse_id(self) -> str | None:
"""Parse an ID describing the abstract tool. This is not the
GUID tracked by the tool shed but the simple id (there may be
multiple tools loaded in Galaxy with this same simple id).
"""
@abstractmethod
- def parse_version(self) -> Optional[str]:
+ def parse_version(self) -> str | None:
"""Parse a version describing the abstract tool."""
- def parse_class(self) -> Optional[str]:
+ def parse_class(self) -> str | None:
"""Parse the class of the tool."""
return None
- def parse_tool_module(self) -> Optional[Tuple[str, str]]:
+ def parse_tool_module(self) -> tuple[str, str] | None:
"""Load Tool class from a custom module. (Optional).
If not None, return pair containing module and class (as strings).
@@ -176,7 +173,7 @@ class ToolSource(metaclass=ABCMeta):
"""
return None
- def parse_tool_type(self) -> Optional[str]:
+ def parse_tool_type(self) -> str | None:
"""Load simple tool type string (e.g. 'data_source', 'default')."""
return None
@@ -192,19 +189,19 @@ class ToolSource(metaclass=ABCMeta):
"""
@abstractmethod
- def parse_icon(self) -> Optional[str]:
+ def parse_icon(self) -> str | None:
"""Return icon path for tool."""
- def parse_edam_operations(self) -> List[str]:
+ def parse_edam_operations(self) -> list[str]:
"""Parse list of edam operation codes."""
return []
- def parse_edam_topics(self) -> List[str]:
+ def parse_edam_topics(self) -> list[str]:
"""Parse list of edam topic codes."""
return []
@abstractmethod
- def parse_xrefs(self) -> List[XrefDict]:
+ def parse_xrefs(self) -> list[XrefDict]:
"""Parse list of external resource URIs and types."""
def parse_display_interface(self, default):
@@ -230,15 +227,15 @@ class ToolSource(metaclass=ABCMeta):
def parse_command(self):
"""Return string contianing command to run."""
- def parse_shell_command(self) -> Optional[str]:
+ def parse_shell_command(self) -> str | None:
"""Return string that after input binding can be executed."""
return None
- def parse_base_command(self) -> Optional[List[str]]:
+ def parse_base_command(self) -> list[str] | None:
"""Return string containing script entrypoint."""
return None
- def parse_arguments(self) -> Optional[List[str]]:
+ def parse_arguments(self) -> list[str] | None:
"""Return list of strings to append to base_command."""
return None
@@ -329,12 +326,12 @@ class ToolSource(metaclass=ABCMeta):
@abstractmethod
def parse_requirements(
self,
- ) -> Tuple[
+ ) -> tuple[
"ToolRequirements",
- List["ContainerDescription"],
- List["ToolResourceRequirement"],
- List["JavascriptRequirement"],
- List["CredentialsRequirement"],
+ list["ContainerDescription"],
+ list["ToolResourceRequirement"],
+ list["JavascriptRequirement"],
+ list["CredentialsRequirement"],
]:
"""Return triple of ToolRequirement, ContainerDescription, ResourceRequirement, JavascriptRequirement, and CredentialsRequirement objects."""
@@ -361,7 +358,7 @@ class ToolSource(metaclass=ABCMeta):
@abstractmethod
def parse_outputs(
self, app: Optional["ToolOutputActionApp"]
- ) -> Tuple[Dict[str, "ToolOutputBase"], Dict[str, "ToolOutputCollection"]]:
+ ) -> tuple[dict[str, "ToolOutputBase"], dict[str, "ToolOutputCollection"]]:
"""Return a pair of output and output collections ordered
dictionaries for use by Tool.
"""
@@ -380,7 +377,7 @@ class ToolSource(metaclass=ABCMeta):
return [], []
@abstractmethod
- def parse_help(self) -> Optional[HelpContent]:
+ def parse_help(self) -> HelpContent | None:
"""Return help text for tool or None if the tool doesn't define help text.
The returned object contains the help text and an indication if it is reStructuredText
@@ -392,15 +389,15 @@ class ToolSource(metaclass=ABCMeta):
"""Return tool profile version as Galaxy major e.g. 16.01 or 16.04."""
@abstractmethod
- def parse_license(self) -> Optional[str]:
+ def parse_license(self) -> str | None:
"""Return license corresponding to tool wrapper."""
- def parse_citations(self) -> List[Citation]:
+ def parse_citations(self) -> list[Citation]:
"""Return a list of citations."""
return []
@abstractmethod
- def parse_python_template_version(self) -> Optional[packaging.version.Version]:
+ def parse_python_template_version(self) -> packaging.version.Version | None:
"""
Return minimum python version that the tool template has been developed against.
"""
@@ -422,7 +419,7 @@ class ToolSource(metaclass=ABCMeta):
return []
@property
- def macro_paths(self) -> List[str]:
+ def macro_paths(self) -> list[str]:
return []
@property
@@ -439,8 +436,7 @@ class ToolSource(metaclass=ABCMeta):
return {"tests": []}
def __str__(self):
- source_path = self.source_path
- if source_path:
+ if source_path := self.source_path:
as_str = f"{self.__class__.__name__}[{source_path}]"
else:
as_str = f"{self.__class__.__name__}[In-memory]"
@@ -475,7 +471,6 @@ class PagesSource:
class DynamicOptions(metaclass=ABCMeta):
-
def elem(self) -> Element:
# For things in transition that still depend on XML - provide a way
# to grab it and just throw an error if feature is attempted to be
@@ -483,22 +478,21 @@ class DynamicOptions(metaclass=ABCMeta):
raise NotImplementedError(NOT_IMPLEMENTED_MESSAGE)
@abstractmethod
- def get_dynamic_options_code(self) -> Optional[str]:
+ def get_dynamic_options_code(self) -> str | None:
"""If dynamic options are a piece of code to eval, return it."""
@abstractmethod
- def get_data_table_name(self) -> Optional[str]:
+ def get_data_table_name(self) -> str | None:
"""If dynamic options are loaded from a data table, return the name."""
@abstractmethod
- def get_index_file_name(self) -> Optional[str]:
+ def get_index_file_name(self) -> str | None:
"""If dynamic options are loaded from an index file, return the name."""
class DrillDownDynamicOptions(metaclass=ABCMeta):
-
@abstractmethod
- def from_code_block(self) -> Optional[str]:
+ def from_code_block(self) -> str | None:
"""Get a code block to do an eval on."""
@@ -549,7 +543,7 @@ class InputSource(metaclass=ABCMeta):
"""Return the type of this input."""
@abstractmethod
- def parse_extensions(self) -> List[str]:
+ def parse_extensions(self) -> list[str]:
"""Return list of extensions"""
def parse_help(self):
@@ -562,7 +556,7 @@ class InputSource(metaclass=ABCMeta):
"""
return None
- def parse_validators(self) -> List[AnyValidatorModel]:
+ def parse_validators(self) -> list[AnyValidatorModel]:
"""Return an XML description of sanitizers. This is a stop gap
until we can rework galaxy.tools.parameters.validation to not
explicitly depend on XML.
@@ -575,7 +569,7 @@ class InputSource(metaclass=ABCMeta):
default = self.default_optional
return self.get_bool("optional", default)
- def parse_dynamic_options(self) -> Optional[DynamicOptions]:
+ def parse_dynamic_options(self) -> DynamicOptions | None:
"""Return an optional element describing dynamic options.
These options are still very XML based but as they are adapted to the infrastructure, the return
@@ -584,19 +578,17 @@ class InputSource(metaclass=ABCMeta):
return None
def parse_drill_down_dynamic_options(
- self, tool_data_path: Optional[str] = None
+ self, tool_data_path: str | None = None
) -> Optional["DrillDownDynamicOptions"]:
return None
- def parse_static_options(self) -> List[Tuple[str, str, bool]]:
+ def parse_static_options(self) -> list[tuple[str, str, bool]]:
"""Return list of static options if this is a select type without
defining a dynamic options.
"""
return []
- def parse_drill_down_static_options(
- self, tool_data_path: Optional[str] = None
- ) -> Optional[List["DrillDownOptionsDict"]]:
+ def parse_drill_down_static_options(self, tool_data_path: str | None = None) -> list["DrillDownOptionsDict"] | None:
return None
def parse_conversion_tuples(self):
@@ -614,7 +606,7 @@ class InputSource(metaclass=ABCMeta):
def parse_when_input_sources(self):
raise NotImplementedError(NOT_IMPLEMENTED_MESSAGE)
- def parse_default(self) -> Optional[Dict[str, Any]]:
+ def parse_default(self) -> dict[str, Any] | None:
return None
@@ -623,13 +615,13 @@ class PageSource(metaclass=ABCMeta):
return None
@abstractmethod
- def parse_input_sources(self) -> List[InputSource]:
+ def parse_input_sources(self) -> list[InputSource]:
"""Return a list of InputSource objects."""
AnyTestCollectionDefDict = Union["JsonTestCollectionDefDict", "XmlTestCollectionDefDict"]
TestCollectionDefElementObject = Union[AnyTestCollectionDefDict, "ToolSourceTestInput"]
-TestCollectionAttributeDict = Dict[str, Any]
+TestCollectionAttributeDict = dict[str, Any]
CollectionType = str
@@ -650,9 +642,9 @@ class TestCollectionDefElementInternal(TypedDict):
class XmlTestCollectionDefDict(TypedDict):
model_class: Literal["TestCollectionDef"]
attributes: TestCollectionAttributeDict
- collection_type: Optional[CollectionType]
- fields: Optional[List[FieldDict]]
- elements: List[TestCollectionDefElementDict]
+ collection_type: CollectionType | None
+ fields: list[FieldDict] | None
+ elements: list[TestCollectionDefElementDict]
name: str
@@ -670,13 +662,12 @@ def xml_data_input_to_json(xml_input: ToolSourceTestInput) -> Optional["JsonTest
_copy_if_exists(attributes, as_dict, "dbkey")
_copy_if_exists(attributes, as_dict, "ftype", "filetype")
_copy_if_exists(attributes, as_dict, "composite_data", only_if_value=True)
- tags = attributes.get("tags")
- if tags:
+ if tags := attributes.get("tags"):
as_dict["tags"] = [t.strip() for t in tags.split(",")]
return as_dict
-def _copy_if_exists(attributes, as_dict, name: str, as_name: Optional[str] = None, only_if_value: bool = False):
+def _copy_if_exists(attributes, as_dict, name: str, as_name: str | None = None, only_if_value: bool = False):
if name in attributes:
value = attributes[name]
if not value and only_if_value:
@@ -688,13 +679,11 @@ def _copy_if_exists(attributes, as_dict, name: str, as_name: Optional[str] = Non
class TestCollectionDef:
__test__ = False # Prevent pytest from discovering this class (issue #12071)
- elements: List[TestCollectionDefElementInternal]
- collection_type: Optional[str]
- fields: Optional[List[FieldDict]]
+ elements: list[TestCollectionDefElementInternal]
+ collection_type: str | None
+ fields: list[FieldDict] | None
- def __init__(
- self, attrib, name, collection_type: Optional[str], elements, fields: Optional[List[FieldDict]] = None
- ):
+ def __init__(self, attrib, name, collection_type: str | None, elements, fields: list[FieldDict] | None = None):
self.attrib = attrib
self.collection_type = collection_type
self.elements = elements
@@ -713,7 +702,7 @@ class TestCollectionDef:
identifier=identifier, **element_object._test_format_to_dict()
)
else:
- input_as_dict: Optional[JsonTestDatasetDefDict] = xml_data_input_to_json(element_object)
+ input_as_dict: JsonTestDatasetDefDict | None = xml_data_input_to_json(element_object)
if input_as_dict is not None:
as_dict = JsonTestCollectionDefDatasetElementDict(
identifier=identifier,
@@ -761,7 +750,7 @@ class TestCollectionDef:
@staticmethod
def from_dict(
- as_dict: Union[AnyTestCollectionDefDict, JsonTestCollectionDefCollectionElementDict],
+ as_dict: AnyTestCollectionDefDict | JsonTestCollectionDefCollectionElementDict,
) -> "TestCollectionDef":
if "model_class" in as_dict:
xml_as_dict = cast(XmlTestCollectionDefDict, as_dict)
@@ -790,7 +779,7 @@ class TestCollectionDef:
) -> TestCollectionDefElementInternal:
element_class = element_dict.get("class")
identifier = element_dict["identifier"]
- element_def: Union[TestCollectionDef, ToolSourceTestInput]
+ element_def: TestCollectionDef | ToolSourceTestInput
if element_class == "Collection":
collection_element_dict = cast(JsonTestCollectionDefCollectionElementDict, element_dict)
element_def = TestCollectionDef.from_dict(collection_element_dict)
@@ -822,7 +811,7 @@ class TestCollectionDef:
class RequiredFiles:
- def __init__(self, includes: List[Dict], excludes: List[Dict], extend_default_excludes: bool):
+ def __init__(self, includes: list[dict], excludes: list[dict], extend_default_excludes: bool):
self.includes = includes
self.excludes = excludes
self.extend_default_excludes = extend_default_excludes
@@ -830,12 +819,12 @@ class RequiredFiles:
@staticmethod
def from_dict(as_dict):
extend_default_excludes: bool = as_dict.get("extend_default_excludes", True)
- includes: List = as_dict.get("includes", [])
- excludes: List = as_dict.get("excludes", [])
+ includes: list = as_dict.get("includes", [])
+ excludes: list = as_dict.get("excludes", [])
return RequiredFiles(includes, excludes, extend_default_excludes)
- def find_required_files(self, tool_directory: str) -> List[str]:
- def matches(ie_list: List, rel_path: str):
+ def find_required_files(self, tool_directory: str) -> list[str]:
+ def matches(ie_list: list, rel_path: str):
for ie_item in ie_list:
ie_item_path = ie_item["path"]
ie_item_type = ie_item.get("path_type", "literal")
@@ -859,7 +848,7 @@ class RequiredFiles:
excludes.append({"path": "test-data", "path_type": "prefix"})
excludes.append({"path": ".hg", "path_type": "prefix"})
- files: List[str] = []
+ files: list[str] = []
for dirpath, _, filenames in safe_walk(tool_directory):
for filename in filenames:
rel_path = join(dirpath, filename).replace(tool_directory + os.path.sep, "")
@@ -871,7 +860,7 @@ class RequiredFiles:
class TestCollectionOutputDef:
__test__ = False # Prevent pytest from discovering this class (issue #12071)
- def __init__(self, name, attrib, element_tests, element_count: Optional[int] = None):
+ def __init__(self, name, attrib, element_tests, element_count: int | None = None):
self.name = name
self.collection_type = attrib.get("type", None)
if element_count is not None:
diff --git a/lib/galaxy/tool_util/parser/output_actions.py b/lib/galaxy/tool_util/parser/output_actions.py
index 9c868fdd8b5..efd286a38e4 100644
--- a/lib/galaxy/tool_util/parser/output_actions.py
+++ b/lib/galaxy/tool_util/parser/output_actions.py
@@ -7,7 +7,6 @@ import os.path
import re
from typing import (
Any,
- List,
)
from typing_extensions import Protocol
@@ -71,7 +70,7 @@ class ToolOutputActionConditionalWhen(ToolOutputActionGroup):
tag = "when"
@classmethod
- def from_elem(cls, app: ToolOutputActionApp, conditional_name_parts: List[str], when_elem):
+ def from_elem(cls, app: ToolOutputActionApp, conditional_name_parts: list[str], when_elem):
"""Loads the proper when by attributes of elem"""
when_value = when_elem.get("value", None)
if when_value is not None:
@@ -84,7 +83,7 @@ class ToolOutputActionConditionalWhen(ToolOutputActionGroup):
)
raise TypeError("When type not implemented")
- def __init__(self, app: ToolOutputActionApp, conditional_name_parts: List[str], config_elem, value):
+ def __init__(self, app: ToolOutputActionApp, conditional_name_parts: list[str], config_elem, value):
super().__init__(app, config_elem)
self.conditional_name_parts = conditional_name_parts
self.value = value
@@ -115,7 +114,7 @@ class ValueToolOutputActionConditionalWhen(ToolOutputActionConditionalWhen):
class DatatypeIsInstanceToolOutputActionConditionalWhen(ToolOutputActionConditionalWhen):
tag = "when datatype_isinstance"
- def __init__(self, app: ToolOutputActionApp, conditional_name_parts: List[str], config_elem, value):
+ def __init__(self, app: ToolOutputActionApp, conditional_name_parts: list[str], config_elem, value):
super().__init__(app, conditional_name_parts, config_elem, value)
self.value = type(app.datatypes_registry.get_datatype_by_extension(value))
diff --git a/lib/galaxy/tool_util/parser/output_collection_def.py b/lib/galaxy/tool_util/parser/output_collection_def.py
index 5e2f2ddd7bf..cb3470525df 100644
--- a/lib/galaxy/tool_util/parser/output_collection_def.py
+++ b/lib/galaxy/tool_util/parser/output_collection_def.py
@@ -3,10 +3,6 @@ dataset collection after jobs are finished.
"""
import abc
-from typing import (
- List,
- Optional,
-)
from galaxy.tool_util_models.tool_outputs import (
DatasetCollectionDescriptionT,
@@ -95,10 +91,10 @@ def dataset_collection_description(**kwargs):
class DatasetCollectionDescription(metaclass=abc.ABCMeta):
discover_via: DiscoverViaT
- default_ext: Optional[str]
+ default_ext: str | None
default_visible: bool
assign_primary_output: bool
- directory: Optional[str]
+ directory: str | None
recurse: bool
match_relative_path: bool
@@ -132,7 +128,7 @@ class DatasetCollectionDescription(metaclass=abc.ABCMeta):
return self.to_model().model_dump()
@property
- def discover_patterns(self) -> List[str]:
+ def discover_patterns(self) -> list[str]:
return []
@@ -210,7 +206,7 @@ class FilePatternDatasetCollectionDescription(DatasetCollectionDescription):
)
@property
- def discover_patterns(self) -> List[str]:
+ def discover_patterns(self) -> list[str]:
return [self.pattern]
diff --git a/lib/galaxy/tool_util/parser/output_objects.py b/lib/galaxy/tool_util/parser/output_objects.py
index ecab9d82c88..ddd18822979 100644
--- a/lib/galaxy/tool_util/parser/output_objects.py
+++ b/lib/galaxy/tool_util/parser/output_objects.py
@@ -1,13 +1,8 @@
import abc
+from collections.abc import Sequence
from typing import (
Any,
- Dict,
- List,
- Optional,
- Sequence,
- Type,
TYPE_CHECKING,
- Union,
)
from typing_extensions import TypedDict
@@ -36,20 +31,20 @@ if TYPE_CHECKING:
from galaxy.tool_util.parser import ToolSource
if TYPE_CHECKING:
- from typing_extensions import TypeIs # Supported only under Python >=3.8
+ from typing_extensions import TypeIs
class ChangeFormatModel(TypedDict):
- value: Optional[str]
- format: Optional[str]
- input: Optional[str]
- input_dataset: Optional[str]
- check_attribute: Optional[str]
+ value: str | None
+ format: str | None
+ input: str | None
+ input_dataset: str | None
+ check_attribute: str | None
class ToolOutputBase(Dictifiable):
name: str
- label: Optional[str]
+ label: str | None
hidden: bool
precreate_directory: bool
@@ -57,10 +52,10 @@ class ToolOutputBase(Dictifiable):
self,
name: str,
output_type: str,
- label: Optional[str] = None,
- filters: Optional[List[Element]] = None,
+ label: str | None = None,
+ filters: list[Element] | None = None,
hidden: bool = False,
- from_expression: Optional[str] = None,
+ from_expression: str | None = None,
) -> None:
super().__init__()
self.name = name
@@ -76,7 +71,7 @@ class ToolOutputBase(Dictifiable):
return super().to_dict(view=view, value_mapper=value_mapper)
@property
- def output_discover_patterns(self) -> List[str]:
+ def output_discover_patterns(self) -> list[str]:
return []
@abc.abstractmethod
@@ -108,16 +103,16 @@ class ToolOutput(ToolOutputBase):
def __init__(
self,
name: str,
- format: Optional[str] = None,
- format_source: Optional[str] = None,
- metadata_source: Optional[str] = None,
- parent: Optional[str] = None,
- label: Optional[str] = None,
- filters: Optional[List[Element]] = None,
- actions: Optional[ToolOutputActionGroup] = None,
+ format: str | None = None,
+ format_source: str | None = None,
+ metadata_source: str | None = None,
+ parent: str | None = None,
+ label: str | None = None,
+ filters: list[Element] | None = None,
+ actions: ToolOutputActionGroup | None = None,
hidden: bool = False,
implicit: bool = False,
- from_expression: Optional[str] = None,
+ from_expression: str | None = None,
) -> None:
super().__init__(
name, output_type="data", label=label, filters=filters, hidden=hidden, from_expression=from_expression
@@ -129,13 +124,13 @@ class ToolOutput(ToolOutputBase):
self.actions = actions
# Initialize default values
- self.change_format: List[ChangeFormatModel] = []
+ self.change_format: list[ChangeFormatModel] = []
self.implicit = implicit
- self.from_work_dir: Optional[str] = None
+ self.from_work_dir: str | None = None
self.precreate_directory: bool = False
- self.dataset_collector_descriptions: List[DatasetCollectionDescription] = []
- self.default_identifier_source: Optional[str] = None
- self.count: Optional[int] = None
+ self.dataset_collector_descriptions: list[DatasetCollectionDescription] = []
+ self.default_identifier_source: str | None = None
+ self.count: int | None = None
# Tuple emulation
@@ -184,7 +179,7 @@ class ToolOutput(ToolOutputBase):
)
@staticmethod
- def from_dict(name: str, output_dict: Dict[str, Any], app: Optional[ToolOutputActionApp] = None) -> "ToolOutput":
+ def from_dict(name: str, output_dict: dict[str, Any], app: ToolOutputActionApp | None = None) -> "ToolOutput":
output = ToolOutput(name)
output.format = output_dict.get("format") or "data"
output.change_format = []
@@ -205,13 +200,13 @@ class ToolOutput(ToolOutputBase):
return output
@property
- def output_discover_patterns(self) -> List[str]:
+ def output_discover_patterns(self) -> list[str]:
return _merge_dataset_collector_descriptions_patterns(self.dataset_collector_descriptions)
class ToolExpressionOutput(ToolOutputBase):
dict_collection_visible_keys = ("name", "format", "label", "hidden", "output_type")
- path: Optional[str]
+ path: str | None
def __init__(self, name, output_type, from_expression, label=None, filters=None, actions=None, hidden=False):
super().__init__(name, output_type=output_type, label=label, filters=filters, hidden=hidden)
@@ -232,12 +227,12 @@ class ToolExpressionOutput(ToolOutputBase):
self.dataset_collector_descriptions = []
def to_model(self) -> ToolOutputModel:
- model_class: Union[
- Type[ToolOutputIntegerModel],
- Type[ToolOutputFloatModel],
- Type[ToolOutputBooleanModel],
- Type[ToolOutputTextModel],
- ]
+ model_class: (
+ type[ToolOutputIntegerModel]
+ | type[ToolOutputFloatModel]
+ | type[ToolOutputBooleanModel]
+ | type[ToolOutputTextModel]
+ )
model_type = self.output_type
if self.output_type == "integer":
model_class = ToolOutputIntegerModel
@@ -291,12 +286,12 @@ class ToolOutputCollection(ToolOutputBase):
self,
name: str,
structure: "ToolOutputCollectionStructure",
- label: Optional[str] = None,
- filters: Optional[List[Element]] = None,
+ label: str | None = None,
+ filters: list[Element] | None = None,
hidden: bool = False,
default_format: str = "data",
- default_format_source: Optional[str] = None,
- default_metadata_source: Optional[str] = None,
+ default_format_source: str | None = None,
+ default_metadata_source: str | None = None,
inherit_format: bool = False,
inherit_metadata: bool = False,
) -> None:
@@ -304,14 +299,14 @@ class ToolOutputCollection(ToolOutputBase):
self.collection = True
self.default_format = default_format
self.structure = structure
- self.outputs: Dict[str, ToolOutput] = {}
+ self.outputs: dict[str, ToolOutput] = {}
self.inherit_format = inherit_format
self.inherit_metadata = inherit_metadata
self.metadata_source = default_metadata_source
self.format_source = default_format_source
- self.change_format: List = [] # TODO: not implemented
+ self.change_format: list = [] # TODO: not implemented
def known_outputs(self, inputs, type_registry):
if self.dynamic_structure:
@@ -396,7 +391,7 @@ class ToolOutputCollection(ToolOutputBase):
)
@staticmethod
- def from_dict(name: str, output_dict, app: Optional[ToolOutputActionApp] = None) -> "ToolOutputCollection":
+ def from_dict(name: str, output_dict, app: ToolOutputActionApp | None = None) -> "ToolOutputCollection":
structure = ToolOutputCollectionStructure.from_dict(output_dict["structure"])
rval = ToolOutputCollection(
name,
@@ -413,7 +408,7 @@ class ToolOutputCollection(ToolOutputBase):
return rval
@property
- def output_discover_patterns(self) -> List[str]:
+ def output_discover_patterns(self) -> list[str]:
return self.structure.output_discover_patterns
@@ -422,20 +417,20 @@ def tool_output_is_collection(tool_output: ToolOutputBase) -> "TypeIs[ToolOutput
class ToolOutputCollectionStructure:
- collection_type: Optional[str]
- collection_type_source: Optional[str]
- collection_type_from_rules: Optional[str]
- structured_like: Optional[str]
- dataset_collector_descriptions: Optional[List[DatasetCollectionDescription]]
+ collection_type: str | None
+ collection_type_source: str | None
+ collection_type_from_rules: str | None
+ structured_like: str | None
+ dataset_collector_descriptions: list[DatasetCollectionDescription] | None
dynamic: bool
def __init__(
self,
- collection_type: Optional[str],
- collection_type_source: Optional[str] = None,
- collection_type_from_rules: Optional[str] = None,
- structured_like: Optional[str] = None,
- dataset_collector_descriptions: Optional[List[DatasetCollectionDescription]] = None,
+ collection_type: str | None,
+ collection_type_source: str | None = None,
+ collection_type_from_rules: str | None = None,
+ structured_like: str | None = None,
+ dataset_collector_descriptions: list[DatasetCollectionDescription] | None = None,
fields=None,
) -> None:
self.collection_type = collection_type
@@ -478,7 +473,7 @@ class ToolOutputCollectionStructure:
return collection_prototype
def to_dict(self):
- discover_datasets: List[Dict[str, Any]] = []
+ discover_datasets: list[dict[str, Any]] = []
if self.dataset_collector_descriptions:
discover_datasets = [d.to_model().model_dump() for d in self.dataset_collector_descriptions]
return {
@@ -501,7 +496,7 @@ class ToolOutputCollectionStructure:
return structure
@property
- def output_discover_patterns(self) -> List[str]:
+ def output_discover_patterns(self) -> list[str]:
if not self.dataset_collector_descriptions:
return []
else:
@@ -509,8 +504,8 @@ class ToolOutputCollectionStructure:
def _merge_dataset_collector_descriptions_patterns(
- dataset_collector_descriptions: List[DatasetCollectionDescription],
-) -> List[str]:
+ dataset_collector_descriptions: list[DatasetCollectionDescription],
+) -> list[str]:
patterns = []
for description in dataset_collector_descriptions:
patterns.extend(description.discover_patterns)
diff --git a/lib/galaxy/tool_util/parser/parameter_validators.py b/lib/galaxy/tool_util/parser/parameter_validators.py
index 6fabc8ae798..576546305fc 100644
--- a/lib/galaxy/tool_util/parser/parameter_validators.py
+++ b/lib/galaxy/tool_util/parser/parameter_validators.py
@@ -1,16 +1,11 @@
import json
+from collections.abc import Sequence
from typing import (
Any,
cast,
- Dict,
- List,
- Optional,
- Sequence,
- Union,
+ get_args,
)
-from typing_extensions import get_args
-
from galaxy.tool_util_models.parameter_validators import (
AnyValidatorModel,
DatasetMetadataEqualParameterValidatorModel,
@@ -47,7 +42,7 @@ class UnsafeValidatorConfiguredInUntrustedContext(AssertionError):
pass
-def parse_dict_validators(validator_dicts: List[Dict[str, Any]], trusted: bool) -> List[AnyValidatorModel]:
+def parse_dict_validators(validator_dicts: list[dict[str, Any]], trusted: bool) -> list[AnyValidatorModel]:
validator_models = []
for validator_dict in validator_dicts:
validator = DiscriminatedAnyValidatorModel.validate_python(validator_dict)
@@ -59,15 +54,15 @@ def parse_dict_validators(validator_dicts: List[Dict[str, Any]], trusted: bool)
return validator_models
-def parse_xml_validators(input_elem: Element) -> List[AnyValidatorModel]:
- validator_els: List[Element] = input_elem.findall("validator") or []
+def parse_xml_validators(input_elem: Element) -> list[AnyValidatorModel]:
+ validator_els: list[Element] = input_elem.findall("validator") or []
models = []
for validator_el in validator_els:
models.append(parse_xml_validator(validator_el))
return models
-def static_validators(validator_models: List[AnyValidatorModel]) -> List[AnyValidatorModel]:
+def static_validators(validator_models: list[AnyValidatorModel]) -> list[AnyValidatorModel]:
static_validators = []
for validator_model in validator_models:
if validator_model._static:
@@ -228,20 +223,19 @@ def parse_xml_validator(validator_el: Element) -> AnyValidatorModel:
raise ValueError(f"Unhandled 'type' attribute in validator {validator_type}")
-def _parse_message(xml_el: Element) -> Optional[str]:
+def _parse_message(xml_el: Element) -> str | None:
message = xml_el.get("message")
return message
-def _parse_int(xml_el: Element, attribute: str) -> Optional[int]:
- raw_value = xml_el.get(attribute)
- if raw_value:
+def _parse_int(xml_el: Element, attribute: str) -> int | None:
+ if raw_value := xml_el.get(attribute):
return int(raw_value)
else:
return None
-def _parse_number(xml_el: Element, attribute: str) -> Optional[Union[float, int]]:
+def _parse_number(xml_el: Element, attribute: str) -> float | int | None:
raw_value = xml_el.get(attribute)
if raw_value and ("." in raw_value or "e" in raw_value or "inf" in raw_value):
return float(raw_value)
@@ -259,7 +253,7 @@ def _parse_bool(xml_el: Element, attribute: str, default_value: bool) -> bool:
return asbool(xml_el.get(attribute, default_value))
-def _parse_str_list(xml_el: Element, attribute: str) -> List[str]:
+def _parse_str_list(xml_el: Element, attribute: str) -> list[str]:
raw_value = xml_el.get(attribute)
if not raw_value:
return []
@@ -272,7 +266,7 @@ def _parse_json_value(xml_el: Element) -> Any:
return value
-def _parse_metadata_column(xml_el: Element) -> Union[int, str]:
+def _parse_metadata_column(xml_el: Element) -> int | str:
column = xml_el.get("metadata_column", 0)
try:
return int(column)
@@ -280,8 +274,8 @@ def _parse_metadata_column(xml_el: Element) -> Union[int, str]:
return column
-def static_tool_validators(validators: Sequence[ParameterValidatorModel]) -> List[StaticValidatorModel]:
- static_validators: List[StaticValidatorModel] = []
+def static_tool_validators(validators: Sequence[ParameterValidatorModel]) -> list[StaticValidatorModel]:
+ static_validators: list[StaticValidatorModel] = []
for validator in validators:
if isinstance(validator, StaticValidatorModel):
static_validators.append(validator)
diff --git a/lib/galaxy/tool_util/parser/util.py b/lib/galaxy/tool_util/parser/util.py
index 0dbc476ef0c..93f319cf7e8 100644
--- a/lib/galaxy/tool_util/parser/util.py
+++ b/lib/galaxy/tool_util/parser/util.py
@@ -1,10 +1,6 @@
from collections import OrderedDict
from typing import (
- List,
- Optional,
- Tuple,
TYPE_CHECKING,
- Union,
)
from packaging.version import Version
@@ -49,9 +45,7 @@ def parse_profile_version(tool_source: "ToolSource") -> float:
return float(tool_source.parse_profile())
-def parse_tool_version_with_defaults(
- id: Optional[str], tool_source: "ToolSource", profile: Optional[Version] = None
-) -> str:
+def parse_tool_version_with_defaults(id: str | None, tool_source: "ToolSource", profile: Version | None = None) -> str:
if profile is None:
profile = Version(tool_source.parse_profile())
@@ -70,7 +64,7 @@ def boolean_is_checked(input_source: "InputSource"):
return input_source.get_bool("checked", None if nullable else False)
-def boolean_true_and_false_values(input_source, profile: Optional[Union[float, str]] = None) -> Tuple[str, str]:
+def boolean_true_and_false_values(input_source, profile: float | str | None = None) -> tuple[str, str]:
truevalue = input_source.get("truevalue", "true")
falsevalue = input_source.get("falsevalue", "false")
if profile and Version(str(profile)) >= Version("23.1"):
@@ -87,9 +81,9 @@ def boolean_true_and_false_values(input_source, profile: Optional[Union[float, s
return (truevalue, falsevalue)
-def text_input_is_optional(input_source: "InputSource") -> Tuple[bool, bool]:
+def text_input_is_optional(input_source: "InputSource") -> tuple[bool, bool]:
# Optionality not explicitly defined, default to False
- optional: Optional[bool] = False
+ optional: bool | None = False
optionality_inferred: bool = False
optional = input_source.get("optional", None)
@@ -116,7 +110,7 @@ class ParameterParseException(Exception):
self.message = message
-def multiple_select_value_split(values: Union[str, List[str]]) -> List[str]:
+def multiple_select_value_split(values: str | list[str]) -> list[str]:
# used to split simple strings into lists from both tool XML and from the API for consistency
value_list = []
if not isinstance(values, list):
diff --git a/lib/galaxy/tool_util/parser/xml.py b/lib/galaxy/tool_util/parser/xml.py
index 0e5c3950bed..30d8d8f9038 100644
--- a/lib/galaxy/tool_util/parser/xml.py
+++ b/lib/galaxy/tool_util/parser/xml.py
@@ -5,15 +5,14 @@ import math
import os
import re
import uuid
+from collections.abc import (
+ Iterable,
+ Sequence,
+)
from typing import (
Any,
cast,
- Dict,
- Iterable,
- List,
Optional,
- Sequence,
- Tuple,
TYPE_CHECKING,
)
@@ -137,15 +136,15 @@ def destroy_tree(tree):
del tree
-def parse_change_format(change_format: Iterable[Element]) -> List[ChangeFormatModel]:
- change_models: List[ChangeFormatModel] = []
+def parse_change_format(change_format: Iterable[Element]) -> list[ChangeFormatModel]:
+ change_models: list[ChangeFormatModel] = []
for change_elem in change_format:
for when_elem in change_elem.findall("when"):
- value: Optional[str] = when_elem.get("value", None)
- format_: Optional[str] = when_elem.get("format", None)
- check: Optional[str] = when_elem.get("input", None)
- input_dataset: Optional[str] = None
- check_attribute: Optional[str] = None
+ value: str | None = when_elem.get("value", None)
+ format_: str | None = when_elem.get("format", None)
+ check: str | None = when_elem.get("input", None)
+ input_dataset: str | None = None
+ check_attribute: str | None = None
if check is not None:
if "$" not in check:
check = f"${check}"
@@ -170,7 +169,7 @@ class XmlToolSource(ToolSource):
language = "xml"
def __init__(
- self, xml_tree: ElementTree, source_path: Optional["StrPath"] = None, macro_paths: Optional[List[str]] = None
+ self, xml_tree: ElementTree, source_path: Optional["StrPath"] = None, macro_paths: list[str] | None = None
) -> None:
self.xml_tree = xml_tree
self.root = self.xml_tree.getroot()
@@ -187,7 +186,7 @@ class XmlToolSource(ToolSource):
self.root = None
self._xml_tree = None
- def parse_version(self) -> Optional[str]:
+ def parse_version(self) -> str | None:
return self.root.get("version", None)
def parse_id(self):
@@ -205,8 +204,7 @@ class XmlToolSource(ToolSource):
def parse_action_module(self):
root = self.root
- action_elem = root.find("action")
- if action_elem is not None:
+ if (action_elem := root.find("action")) is not None:
module = action_elem.get("module")
cls = action_elem.get("class")
return module, cls
@@ -232,7 +230,7 @@ class XmlToolSource(ToolSource):
return []
return [edam_topic.text for edam_topic in edam_topics.findall("edam_topic")]
- def parse_xrefs(self) -> List[XrefDict]:
+ def parse_xrefs(self) -> list[XrefDict]:
xrefs = self.root.find("xrefs")
if xrefs is None:
return []
@@ -245,7 +243,7 @@ class XmlToolSource(ToolSource):
def parse_description(self) -> str:
return xml_text(self.root, "description")
- def parse_icon(self) -> Optional[str]:
+ def parse_icon(self) -> str | None:
icon_elem = self.root.find("icon")
return icon_elem.get("src") if icon_elem is not None else None
@@ -264,8 +262,7 @@ class XmlToolSource(ToolSource):
def parse_expression(self):
"""Return string containing command to run."""
- expression_el = self.root.find("expression")
- if expression_el is not None:
+ if (expression_el := self.root.find("expression")) is not None:
expression_type = expression_el.get("type")
if expression_type != "ecma5.1":
raise Exception(f"Unknown expression type [{expression_type}] encountered")
@@ -314,8 +311,7 @@ class XmlToolSource(ToolSource):
def parse_interpreter(self):
interpreter = None
- command_el = self._command_el
- if command_el is not None:
+ if (command_el := self._command_el) is not None:
interpreter = command_el.get("interpreter", None)
if interpreter and not self.legacy_defaults:
log.warning("Deprecated interpreter attribute on command element is now ignored.")
@@ -323,8 +319,7 @@ class XmlToolSource(ToolSource):
return interpreter
def parse_version_command(self):
- version_cmd = self.root.find("version_command")
- if version_cmd is not None:
+ if (version_cmd := self.root.find("version_command")) is not None:
return version_cmd.text
else:
return None
@@ -415,7 +410,7 @@ class XmlToolSource(ToolSource):
elem = self.root
return string_as_bool(elem.get(attribute, default))
- def parse_required_files(self) -> Optional[RequiredFiles]:
+ def parse_required_files(self) -> RequiredFiles | None:
required_files = self.root.find("required_files")
if required_files is None:
return None
@@ -463,15 +458,15 @@ class XmlToolSource(ToolSource):
return provided_metadata_file
- def parse_outputs(self, app: Optional[ToolOutputActionApp] = None):
+ def parse_outputs(self, app: ToolOutputActionApp | None = None):
out_elem = self.root.find("outputs")
- outputs: Dict[str, ToolOutputBase] = {}
- output_collections: Dict[str, ToolOutputCollection] = {}
+ outputs: dict[str, ToolOutputBase] = {}
+ output_collections: dict[str, ToolOutputCollection] = {}
if out_elem is None:
return outputs, output_collections
- data_dict: Dict[str, ToolOutput] = {}
- expression_dict: Dict[str, ToolExpressionOutput] = {}
+ data_dict: dict[str, ToolOutput] = {}
+ expression_dict: dict[str, ToolExpressionOutput] = {}
def _parse(data_elem, **kwds):
output_def = self._parse_output(data_elem, app, **kwds)
@@ -481,7 +476,7 @@ class XmlToolSource(ToolSource):
for _ in out_elem.findall("data"):
_parse(_)
- def _parse_expression(output_elem, app: Optional[ToolOutputActionApp] = None, **kwds):
+ def _parse_expression(output_elem, app: ToolOutputActionApp | None = None, **kwds):
output_def = self._parse_expression_output(output_elem, app, **kwds)
output_def.filters = output_elem.findall("filter")
expression_dict[output_def.name] = output_def
@@ -570,7 +565,7 @@ class XmlToolSource(ToolSource):
def _parse_output(
self,
data_elem,
- app: Optional[ToolOutputActionApp] = None,
+ app: ToolOutputActionApp | None = None,
default_format="data",
default_format_source=None,
default_metadata_source=None,
@@ -613,7 +608,7 @@ class XmlToolSource(ToolSource):
)
return output
- def _parse_expression_output(self, output_elem, app: Optional[ToolOutputActionApp] = None, **kwds):
+ def _parse_expression_output(self, output_elem, app: ToolOutputActionApp | None = None, **kwds):
output_type = output_elem.get("type")
from_expression = output_elem.get("from")
output = ToolExpressionOutput(
@@ -687,7 +682,7 @@ class XmlToolSource(ToolSource):
else:
return string_as_bool(default)
- def parse_help(self) -> Optional[HelpContent]:
+ def parse_help(self) -> HelpContent | None:
help_elem = self.root.find("help")
if help_elem is None:
return None
@@ -697,7 +692,7 @@ class XmlToolSource(ToolSource):
return HelpContent(format=help_format, content=content)
@property
- def macro_paths(self) -> List[str]:
+ def macro_paths(self) -> list[str]:
return self._macro_paths
@property
@@ -705,11 +700,10 @@ class XmlToolSource(ToolSource):
return self._source_path
def parse_tests_to_dict(self) -> ToolSourceTests:
- tests_elem = self.root.find("tests")
- tests: List[ToolSourceTest] = []
+ tests: list[ToolSourceTest] = []
rval: ToolSourceTests = dict(tests=tests)
- if tests_elem is not None:
+ if (tests_elem := self.root.find("tests")) is not None:
for i, test_elem in enumerate(tests_elem.findall("test")):
profile = self.parse_profile()
tests.append(_test_elem_to_dict(test_elem, i, profile))
@@ -725,12 +719,12 @@ class XmlToolSource(ToolSource):
# - Enable buggy interpreter attribute.
return self.root.get("profile", "16.01")
- def parse_license(self) -> Optional[str]:
+ def parse_license(self) -> str | None:
return self.root.get("license")
- def parse_citations(self) -> List[Citation]:
+ def parse_citations(self) -> list[Citation]:
"""Return a list of citations."""
- citations: List[Citation] = []
+ citations: list[Citation] = []
root = self.root
citations_elem = root.find("citations")
if citations_elem is None:
@@ -764,7 +758,7 @@ class XmlToolSource(ToolSource):
return python_template_version
def parse_template_configfiles(self) -> Sequence[TemplateConfigFile]:
- configfiles: List[XmlTemplateConfigFile] = []
+ configfiles: list[XmlTemplateConfigFile] = []
if (conf_parent_elem := self.root.find("configfiles")) is not None:
for conf_elem in conf_parent_elem.findall("configfile"):
name = conf_elem.get("name")
@@ -774,7 +768,7 @@ class XmlToolSource(ToolSource):
return configfiles
def parse_input_configfiles(self) -> Sequence[InputConfigFile]:
- config_files: List[InputConfigFile] = []
+ config_files: list[InputConfigFile] = []
if (conf_parent_elem := self.root.find("configfiles")) is not None:
inputs_elem = conf_parent_elem.find("inputs")
if inputs_elem is not None:
@@ -787,7 +781,7 @@ class XmlToolSource(ToolSource):
return config_files
def parse_file_sources(self) -> Sequence[FileSourceConfigFile]:
- config_files: List[FileSourceConfigFile] = []
+ config_files: list[FileSourceConfigFile] = []
if (conf_parent_elem := self.root.find("configfiles")) is not None:
file_sources_elem = conf_parent_elem.find("file_sources")
if file_sources_elem is not None:
@@ -902,12 +896,12 @@ VALUE_OBJECT_UNSET = object()
def __parse_test_attributes(
output_elem, attrib, parse_elements=False, parse_discovered_datasets=False, profile=None
-) -> Tuple[Optional[str], ToolSourceTestOutputAttributes]:
+) -> tuple[str | None, ToolSourceTestOutputAttributes]:
assert_list = __parse_assert_list(output_elem)
# Allow either file or value to specify a target file to compare result with
# file was traditionally used by outputs and value by extra files.
- file: Optional[str] = attrib.pop("file", attrib.pop("value", None))
+ file: str | None = attrib.pop("file", attrib.pop("value", None))
# File no longer required if an list of assertions was present.
@@ -921,49 +915,49 @@ def __parse_test_attributes(
lines_diff: int = int(attrib.pop("lines_diff", "0"))
# Allow a file size to vary if sim_size compare
delta: int = int(attrib.pop("delta", DEFAULT_DELTA))
- delta_frac: Optional[float] = float(attrib["delta_frac"]) if "delta_frac" in attrib else DEFAULT_DELTA_FRAC
+ delta_frac: float | None = float(attrib["delta_frac"]) if "delta_frac" in attrib else DEFAULT_DELTA_FRAC
sort: bool = string_as_bool(attrib.pop("sort", DEFAULT_SORT))
decompress: bool = string_as_bool(attrib.pop("decompress", DEFAULT_DECOMPRESS))
# `location` may contain an URL to a remote file that will be used to download `file` (if not already present on disk).
- location: Optional[str] = attrib.get("location")
+ location: str | None = attrib.get("location")
if location and file is None:
file = os.path.basename(location) # If no file specified, try to get filename from URL last component
# Parameters for "image_diff" comparison
metric: str = attrib.pop("metric", DEFAULT_METRIC)
eps: float = float(attrib.pop("eps", DEFAULT_EPS))
- pin_labels: Optional[Any] = attrib.pop("pin_labels", DEFAULT_PIN_LABELS)
- count: Optional[int] = None
+ pin_labels: Any | None = attrib.pop("pin_labels", DEFAULT_PIN_LABELS)
+ count: int | None = None
try:
count = int(attrib.pop("count"))
except KeyError:
pass
- min: Optional[int] = None
+ min: int | None = None
try:
min = int(attrib.pop("min"))
except KeyError:
pass
- max: Optional[int] = None
+ max: int | None = None
try:
max = int(attrib.pop("max"))
except KeyError:
pass
has_count_assertions = count is not None or min is not None or max is not None
- extra_files: List[Dict[str, Any]] = []
- ftype: Optional[str] = None
+ extra_files: list[dict[str, Any]] = []
+ ftype: str | None = None
if "ftype" in attrib:
ftype = attrib["ftype"]
for extra in output_elem.findall("extra_files"):
extra_files.append(__parse_extra_files_elem(extra))
- metadata: Dict[str, Any] = {}
+ metadata: dict[str, Any] = {}
for metadata_elem in output_elem.findall("metadata"):
metadata[metadata_elem.get("name")] = metadata_elem.get("value")
md5sum = attrib.get("md5", None)
checksum = attrib.get("checksum", None)
- element_tests: Dict[str, Any] = {}
+ element_tests: dict[str, Any] = {}
if parse_elements:
element_tests = __parse_element_tests(output_elem, profile=profile)
- primary_datasets: Dict[str, Any] = {}
+ primary_datasets: dict[str, Any] = {}
if parse_discovered_datasets:
for primary_elem in output_elem.findall("discovered_dataset") or []:
primary_attrib = _element_to_dict(primary_elem)
@@ -1095,7 +1089,7 @@ def __pull_up_params(parent_elem, child_elem):
parent_elem.append(param_elem)
-def __prefix_join(prefix, name, index: Optional[int] = None):
+def __prefix_join(prefix, name, index: int | None = None):
name = name if index is None else f"{name}_{index}"
return name if not prefix else f"{prefix}|{name}"
@@ -1115,7 +1109,7 @@ def __parse_inputs_elems(test_elem, i) -> ToolSourceTestInputs:
return raw_inputs
-_direct_credential_adapter: TypeAdapter = TypeAdapter(List[DirectCredential])
+_direct_credential_adapter: TypeAdapter = TypeAdapter(list[DirectCredential])
def __parse_credentials_elems(test_elem):
@@ -1139,12 +1133,12 @@ def __parse_credentials_elems(test_elem):
def _test_collection_def_dict(elem: Element) -> XmlTestCollectionDefDict:
- elements: List[TestCollectionDefElementDict] = []
- attrib: Dict[str, Any] = _element_to_dict(elem)
+ elements: list[TestCollectionDefElementDict] = []
+ attrib: dict[str, Any] = _element_to_dict(elem)
collection_type = attrib["type"]
name = attrib.get("name", "Unnamed Collection")
for element in elem.findall("element"):
- element_attrib: Dict[str, Any] = _element_to_dict(element)
+ element_attrib: dict[str, Any] = _element_to_dict(element)
element_identifier = element_attrib["name"]
nested_collection_elem = element.find("collection")
element_definition: TestCollectionDefElementObject
@@ -1154,8 +1148,7 @@ def _test_collection_def_dict(elem: Element) -> XmlTestCollectionDefDict:
element_definition = __parse_param_elem(element)
elements.append({"element_identifier": element_identifier, "element_definition": element_definition})
fields_json = "null"
- fields_el = elem.find("fields")
- if fields_el is not None:
+ if (fields_el := elem.find("fields")) is not None:
fields_json = fields_el.text or "null"
fields = json.loads(fields_json)
return XmlTestCollectionDefDict(
@@ -1182,8 +1175,7 @@ def __parse_param_elem(param_elem, i=0) -> ToolSourceTestInput:
if value is None and attrib.get("location", None) is not None:
value = os.path.basename(attrib["location"])
- children_elem = param_elem
- if children_elem is not None:
+ if (children_elem := param_elem) is not None:
# At this time, we can assume having children only
# occurs on DataToolParameter test items but this could
# change and would cause the below parsing to change
@@ -1417,8 +1409,7 @@ class XmlPageSource(PageSource):
self.parent_elem = parent_elem
def parse_display(self):
- display_elem = self.parent_elem.find("display")
- if display_elem is not None:
+ if (display_elem := self.parent_elem.find("display")) is not None:
display = xml_to_string(display_elem)
else:
display = None
@@ -1429,23 +1420,22 @@ class XmlPageSource(PageSource):
class XmlDynamicOptions(DynamicOptions):
-
- def __init__(self, options_elem: Element, dynamic_option_code: Optional[str]):
+ def __init__(self, options_elem: Element, dynamic_option_code: str | None):
self._options_elem = options_elem
self._dynamic_options_code = dynamic_option_code
def elem(self) -> Element:
return self._options_elem
- def get_dynamic_options_code(self) -> Optional[str]:
+ def get_dynamic_options_code(self) -> str | None:
"""If dynamic options are a piece of code to eval, return it."""
return self._dynamic_options_code
- def get_data_table_name(self) -> Optional[str]:
+ def get_data_table_name(self) -> str | None:
"""If dynamic options are loaded from a data table, return the name."""
return self._options_elem.get("from_data_table") if self._options_elem is not None else None
- def get_index_file_name(self) -> Optional[str]:
+ def get_index_file_name(self) -> str | None:
return self._options_elem.get("from_file") if self._options_elem is not None else None
@@ -1481,10 +1471,10 @@ class XmlInputSource(InputSource):
def parse_sanitizer_elem(self):
return self.input_elem.find("sanitizer")
- def parse_validators(self) -> List[AnyValidatorModel]:
+ def parse_validators(self) -> list[AnyValidatorModel]:
return parse_xml_validators(self.input_elem)
- def parse_dynamic_options(self) -> Optional[XmlDynamicOptions]:
+ def parse_dynamic_options(self) -> XmlDynamicOptions | None:
"""Return a XmlDynamicOptions to describe dynamic options if options elem is available."""
options_elem = self.input_elem.find("options")
dynamic_option_code = self.input_elem.get("dynamic_options")
@@ -1494,7 +1484,7 @@ class XmlInputSource(InputSource):
else:
return None
- def parse_static_options(self) -> List[Tuple[str, str, bool]]:
+ def parse_static_options(self) -> list[tuple[str, str, bool]]:
"""
>>> from galaxy.util import parse_xml_string_to_etree
>>> xml = 'A B '
@@ -1517,22 +1507,17 @@ class XmlInputSource(InputSource):
deduplicated_static_options[value] = (text, value, selected)
return list(deduplicated_static_options.values())
- def parse_drill_down_dynamic_options(
- self, tool_data_path: Optional[str] = None
- ) -> Optional[DrillDownDynamicOptions]:
+ def parse_drill_down_dynamic_options(self, tool_data_path: str | None = None) -> DrillDownDynamicOptions | None:
elem = self.input_elem
dynamic_options_raw = elem.get("dynamic_options", None)
- dynamic_options: Optional[str] = str(dynamic_options_raw) if dynamic_options_raw else None
+ dynamic_options: str | None = str(dynamic_options_raw) if dynamic_options_raw else None
if dynamic_options is None:
return None
else:
return XmlDrillDownDynamicOptions(code_block=dynamic_options)
- def parse_drill_down_static_options(
- self, tool_data_path: Optional[str] = None
- ) -> Optional[List[DrillDownOptionsDict]]:
- from_file = self.input_elem.get("from_file", None)
- if from_file:
+ def parse_drill_down_static_options(self, tool_data_path: str | None = None) -> list[DrillDownOptionsDict] | None:
+ if from_file := self.input_elem.get("from_file", None):
if not os.path.isabs(from_file):
assert tool_data_path, "This tool cannot be parsed outside of a Galaxy context"
from_file = os.path.join(tool_data_path, from_file)
@@ -1545,7 +1530,7 @@ class XmlInputSource(InputSource):
if dynamic_options_elem is not None and filter_elem is not None:
return None
- root_options: List[DrillDownOptionsDict] = []
+ root_options: list[DrillDownOptionsDict] = []
options_elem = elem.find("options")
assert options_elem is not None, "Non-dynamic drilldown parameters must supply an options element"
_recurse_drill_down_elems(root_options, options_elem.findall("option"))
@@ -1597,7 +1582,7 @@ class XmlInputSource(InputSource):
sources.append((value, case_page_source))
return sources
- def parse_default(self) -> Optional[Dict[str, Any]]:
+ def parse_default(self) -> dict[str, Any] | None:
def file_default_from_elem(elem):
# TODO: hashes, created_from_basename, etc...
return {"class": "File", "location": elem.get("location")}
@@ -1667,7 +1652,7 @@ class ParallelismInfo:
self.attributes["split_mode"] = "number_of_parts"
-def parse_citation_elem(citation_elem: Element) -> Optional[Citation]:
+def parse_citation_elem(citation_elem: Element) -> Citation | None:
if citation_elem.tag != "citation":
return None
@@ -1683,25 +1668,24 @@ def parse_citation_elem(citation_elem: Element) -> Optional[Citation]:
class XmlDrillDownDynamicOptions(DrillDownDynamicOptions):
-
- def __init__(self, code_block: Optional[str]):
+ def __init__(self, code_block: str | None):
self._code_block = code_block
- def from_code_block(self) -> Optional[str]:
+ def from_code_block(self) -> str | None:
"""Get a code block to do an eval on."""
return self._code_block
-def _element_to_dict(elem: Element) -> Dict[str, Any]:
+def _element_to_dict(elem: Element) -> dict[str, Any]:
# every call to this function needs to be replaced with something more type safe and with
# an actual typed dictionary - but centralizing this hack for now.
return dict(elem.attrib) # type: ignore [arg-type]
-def _recurse_drill_down_elems(options: List[DrillDownOptionsDict], option_elems: List[Element]):
+def _recurse_drill_down_elems(options: list[DrillDownOptionsDict], option_elems: list[Element]):
for option_elem in option_elems:
selected = string_as_bool(option_elem.get("selected", False))
- nested_options: List[DrillDownOptionsDict] = []
+ nested_options: list[DrillDownOptionsDict] = []
value = option_elem.get("value")
assert value
current_option: DrillDownOptionsDict = DrillDownOptionsDict(
diff --git a/lib/galaxy/tool_util/parser/yaml.py b/lib/galaxy/tool_util/parser/yaml.py
index a770b7bdb05..4e0c82c0d91 100644
--- a/lib/galaxy/tool_util/parser/yaml.py
+++ b/lib/galaxy/tool_util/parser/yaml.py
@@ -4,11 +4,6 @@ from copy import deepcopy
from typing import (
Any,
cast,
- Dict,
- List,
- Optional,
- Tuple,
- Union,
)
import packaging.version
@@ -69,10 +64,10 @@ from .util import is_dict
class YamlToolSource(ToolSource):
language = "yaml"
- def __init__(self, root_dict: Dict, source_path=None):
+ def __init__(self, root_dict: dict, source_path=None):
self.root_dict = root_dict
self._source_path = source_path
- self._macro_paths: List[str] = []
+ self._macro_paths: list[str] = []
@property
def source_path(self):
@@ -84,7 +79,7 @@ class YamlToolSource(ToolSource):
def parse_tool_type(self):
return self.root_dict.get("tool_type")
- def parse_tool_module(self) -> Optional[Tuple[str, str]]:
+ def parse_tool_module(self) -> tuple[str, str] | None:
# This should not be settable for user defined tools - placing this here to
# ensure this. If we want to implement tool modules for YAML tools in the future
# ensure class is not GalaxyUserTool.
@@ -93,7 +88,7 @@ class YamlToolSource(ToolSource):
def parse_id(self):
return self.root_dict.get("id")
- def parse_version(self) -> Optional[str]:
+ def parse_version(self) -> str | None:
version_raw = self.root_dict.get("version")
return str(version_raw) if version_raw is not None else None
@@ -105,17 +100,17 @@ class YamlToolSource(ToolSource):
def parse_description(self) -> str:
return self.root_dict.get("description") or ""
- def parse_icon(self) -> Optional[str]:
+ def parse_icon(self) -> str | None:
icon_elem = self.root_dict.get("icon", {})
return icon_elem.get("src") if icon_elem is not None else None
- def parse_edam_operations(self) -> List[str]:
+ def parse_edam_operations(self) -> list[str]:
return self.root_dict.get("edam_operations") or []
- def parse_edam_topics(self) -> List[str]:
+ def parse_edam_topics(self) -> list[str]:
return self.root_dict.get("edam_topics") or []
- def parse_xrefs(self) -> List[XrefDict]:
+ def parse_xrefs(self) -> list[XrefDict]:
xrefs = self.root_dict.get("xrefs") or []
return [XrefDict(value=xref["value"], type=xref["type"]) for xref in xrefs if xref["type"]]
@@ -134,14 +129,14 @@ class YamlToolSource(ToolSource):
def parse_expression(self):
return self.root_dict.get("expression")
- def parse_shell_command(self) -> Optional[str]:
+ def parse_shell_command(self) -> str | None:
return self.root_dict.get("shell_command")
- def parse_base_command(self) -> Optional[List[str]]:
+ def parse_base_command(self) -> list[str] | None:
"""Return string containing script entrypoint."""
return listify(self.root_dict.get("base_command"))
- def parse_arguments(self) -> Optional[List[str]]:
+ def parse_arguments(self) -> list[str] | None:
return self.root_dict.get("arguments")
def parse_environment_variables(self):
@@ -191,7 +186,7 @@ class YamlToolSource(ToolSource):
def parse_stdio(self):
return error_on_exit_code()
- def parse_help(self) -> Optional[HelpContent]:
+ def parse_help(self) -> HelpContent | None:
help = self.root_dict.get("help")
format = "markdown"
if isinstance(help, dict):
@@ -203,7 +198,7 @@ class YamlToolSource(ToolSource):
else:
return None
- def parse_outputs(self, app: Optional[ToolOutputActionApp]):
+ def parse_outputs(self, app: ToolOutputActionApp | None):
outputs = deepcopy(self.root_dict.get("outputs", []))
if isinstance(outputs, MutableMapping):
for name, output_dict in outputs.items():
@@ -279,7 +274,7 @@ class YamlToolSource(ToolSource):
return output_collection
def parse_tests_to_dict(self) -> ToolSourceTests:
- tests: List[ToolSourceTest] = []
+ tests: list[ToolSourceTest] = []
rval: ToolSourceTests = dict(tests=tests)
raw_tests = deepcopy(self.root_dict.get("tests") or [])
@@ -289,7 +284,7 @@ class YamlToolSource(ToolSource):
parameters = self._parse_parameters()
state.validate(parameters, name=f"test case json {i}")
- flat_inputs: Dict[str, Any] = {}
+ flat_inputs: dict[str, Any] = {}
self._flatten_parameters(inputs, parameters, flat_inputs=flat_inputs)
test_dict["inputs"] = flat_inputs
parsed_test = _parse_test(i, test_dict)
@@ -298,12 +293,12 @@ class YamlToolSource(ToolSource):
return rval
def _flatten_parameters(
- self, test_dict: Dict[str, Any], input_models: ToolParameterBundle, flat_inputs, prefix=None
+ self, test_dict: dict[str, Any], input_models: ToolParameterBundle, flat_inputs, prefix=None
):
for parameter in input_models.parameters:
self._flatten_parameter(test_dict, parameter, flat_inputs, prefix=prefix)
- def _flatten_parameter(self, test_dict: Dict[str, Any], parameter: ToolParameterT, flat_inputs, prefix=None):
+ def _flatten_parameter(self, test_dict: dict[str, Any], parameter: ToolParameterT, flat_inputs, prefix=None):
name = parameter.name
if prefix:
flat_name = f"{prefix}|{name}"
@@ -316,12 +311,12 @@ class YamlToolSource(ToolSource):
raw_conditional_state = test_dict[name]
assert isinstance(raw_conditional_state, dict)
- conditional_state = cast(Dict[str, Any], raw_conditional_state)
+ conditional_state = cast(dict[str, Any], raw_conditional_state)
test_parameter = parameter.test_parameter
test_parameter_name = test_parameter.name
- explicit_test_value: Optional[DiscriminatorType] = (
+ explicit_test_value: DiscriminatorType | None = (
conditional_state[test_parameter_name] if test_parameter_name in conditional_state else None
)
test_value = validate_explicit_conditional_test_value(test_parameter_name, explicit_test_value)
@@ -331,7 +326,7 @@ class YamlToolSource(ToolSource):
elif parameter.parameter_type == "gx_repeat":
if name not in test_dict:
test_dict[name] = []
- repeat_instances = cast(List[Dict[str, Any]], test_dict[name])
+ repeat_instances = cast(list[dict[str, Any]], test_dict[name])
if parameter.min:
while len(repeat_instances) < parameter.min:
repeat_instances.append({})
@@ -355,7 +350,7 @@ class YamlToolSource(ToolSource):
def parse_profile(self) -> str:
return self.root_dict.get("profile") or "24.2"
- def parse_license(self) -> Optional[str]:
+ def parse_license(self) -> str | None:
return self.root_dict.get("license")
def parse_interactivetool(self):
@@ -372,7 +367,7 @@ class YamlToolSource(ToolSource):
return json.dumps(self.root_dict, ensure_ascii=False, sort_keys=False)
-def __parse_test_inputs(i: int, test_inputs: Union[list, dict]) -> ToolSourceTestInputs:
+def __parse_test_inputs(i: int, test_inputs: list | dict) -> ToolSourceTestInputs:
inputs: list = test_inputs if isinstance(test_inputs, list) else []
if isinstance(test_inputs, dict):
for key, value in test_inputs.items():
@@ -439,10 +434,10 @@ def _parse_test(i: int, test_dict: dict) -> ToolSourceTest:
return cast(ToolSourceTest, test_dict)
-_direct_credential_adapter: TypeAdapter = TypeAdapter(List[DirectCredential])
+_direct_credential_adapter: TypeAdapter = TypeAdapter(list[DirectCredential])
-def __parse_credentials_yaml(credentials_data) -> Optional[List[DirectCredential]]:
+def __parse_credentials_yaml(credentials_data) -> list[DirectCredential] | None:
"""
Parse credentials from YAML test definition.
@@ -475,7 +470,7 @@ def to_test_assert_list(assertions) -> AssertionList:
if is_dict(assertions):
assertions = map(expand_dict_form, assertions.items())
- assert_list: List[AssertionDict] = []
+ assert_list: list[AssertionDict] = []
for assertion in assertions:
# TODO: not handling nested assertions correctly,
# not sure these are used though.
@@ -574,10 +569,10 @@ class YamlInputSource(InputSource):
sources.append((discriminator, case_page_source))
return sources
- def parse_validators(self) -> List[AnyValidatorModel]:
+ def parse_validators(self) -> list[AnyValidatorModel]:
return parse_dict_validators(self.input_dict.get("validators", []), trusted=self.trusted)
- def parse_static_options(self) -> List[Tuple[str, str, bool]]:
+ def parse_static_options(self) -> list[tuple[str, str, bool]]:
static_options = []
input_dict = self.input_dict
for option in input_dict.get("options", {}):
@@ -587,7 +582,7 @@ class YamlInputSource(InputSource):
static_options.append((label, value, selected))
return static_options
- def parse_default(self) -> Optional[Dict[str, Any]]:
+ def parse_default(self) -> dict[str, Any] | None:
input_dict = self.input_dict
default_def = input_dict.get("default", None)
return default_def
diff --git a/lib/galaxy/tool_util/toolbox/base.py b/lib/galaxy/tool_util/toolbox/base.py
index 1d9f2877ae8..6d3940128be 100644
--- a/lib/galaxy/tool_util/toolbox/base.py
+++ b/lib/galaxy/tool_util/toolbox/base.py
@@ -8,11 +8,8 @@ from collections import namedtuple
from errno import ENOENT
from typing import (
Any,
- Dict,
- FrozenSet,
- List,
+ Literal,
Optional,
- Tuple,
TYPE_CHECKING,
Union,
)
@@ -21,7 +18,6 @@ from uuid import UUID
from markupsafe import escape
from typing_extensions import (
- Literal,
overload,
)
@@ -136,7 +132,7 @@ class ToolBoxRegistryImpl(ToolBoxRegistry):
self.__toolbox.add_tool_to_tool_panel_view(tool, tool_panel_component)
-DynamicToolConfDict = Dict[str, Any]
+DynamicToolConfDict = dict[str, Any]
class AbstractToolTagManager(metaclass=abc.ABCMeta):
@@ -171,12 +167,12 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
workflows optionally in labelled sections.
"""
- _dynamic_tool_confs: List[DynamicToolConfDict]
- _tool_panel_views: Dict[str, ToolPanelView]
+ _dynamic_tool_confs: list[DynamicToolConfDict]
+ _tool_panel_views: dict[str, ToolPanelView]
def __init__(
self,
- config_filenames: List[str],
+ config_filenames: list[str],
tool_root_dir,
app,
view_sources=None,
@@ -192,28 +188,28 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
# information about the tools defined in each shed-related
# shed_tool_conf.xml file.
self._dynamic_tool_confs = []
- self._tools_by_id: Dict[str, Tool] = {}
- self._tools_by_uuid: Dict[UUID, Tool] = {}
+ self._tools_by_id: dict[str, Tool] = {}
+ self._tools_by_uuid: dict[UUID, Tool] = {}
# Tool lineages can contain chains of related tools with different ids
# so each will be present once in the above dictionary. The following
# dictionary can instead hold multiple tools with different versions.
- self._tool_versions_by_id: Dict[str, Dict[Union[str, None], Tool]] = {}
- self._tools_by_old_id: Dict[str, List[Tool]] = {}
- self._workflows_by_id: Dict[str, Workflow] = {}
+ self._tool_versions_by_id: dict[str, dict[str | None, Tool]] = {}
+ self._tools_by_old_id: dict[str, list[Tool]] = {}
+ self._workflows_by_id: dict[str, Workflow] = {}
# Cache for tool's to_dict calls specific to toolbox. Invalidated on toolbox reload
# and whenever a single tool is reloaded/removed (see _invalidate_tool_caches).
- self._tool_to_dict_cache: Dict[str, Dict[str, Any]] = {}
- self._tool_to_dict_cache_admin: Dict[str, Dict[str, Any]] = {}
+ self._tool_to_dict_cache: dict[str, dict[str, Any]] = {}
+ self._tool_to_dict_cache_admin: dict[str, dict[str, Any]] = {}
# Lazily-built sets of curated/edam ids drawn from the loaded tools, used to
# validate favorite-tag / favorite-EDAM additions in O(1) rather than walking
# the full tool list per request.
- self._curated_tool_tags: Optional[FrozenSet[str]] = None
- self._tool_edam_operations: Optional[FrozenSet[str]] = None
- self._tool_edam_topics: Optional[FrozenSet[str]] = None
+ self._curated_tool_tags: frozenset[str] | None = None
+ self._tool_edam_operations: frozenset[str] | None = None
+ self._tool_edam_topics: frozenset[str] | None = None
# In-memory dictionary that defines the layout of the tool panel.
self._tool_panel = ToolPanelElements()
self._index = 0
- self.data_manager_tools: Dict[str, Tool] = {}
+ self.data_manager_tools: dict[str, Tool] = {}
self._lineage_map = LineageMap(app)
# Sets self._integrated_tool_panel and self._integrated_tool_panel_config_has_contents
self._init_integrated_tool_panel(app.config)
@@ -255,7 +251,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
searchable=True,
)
- tool_panel_views_list: List[ToolPanelView] = [
+ tool_panel_views_list: list[ToolPanelView] = [
DefaultToolPanelView(),
MyToolsToolPanelView(),
]
@@ -301,7 +297,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
"""Build a tool tag manager according to app's configuration and return it."""
raise NotImplementedError()
- def _init_tools_from_configs(self, config_filenames: List[str]) -> None:
+ def _init_tools_from_configs(self, config_filenames: list[str]) -> None:
"""Read through all tool config files and initialize tools in each
with init_tools_from_config below.
"""
@@ -409,16 +405,15 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
if tool_uuid in self._tools_by_uuid:
return self._tools_by_uuid[tool_uuid]
- dynamic_tool = self.app.dynamic_tool_manager.get_tool_by_uuid(tool_uuid)
- if dynamic_tool:
+ if dynamic_tool := self.app.dynamic_tool_manager.get_tool_by_uuid(tool_uuid):
return self.load_dynamic_tool(dynamic_tool)
return None
- def panel_views(self) -> List[ToolPanelViewModel]:
+ def panel_views(self) -> list[ToolPanelViewModel]:
return [v.to_model() for v in self._tool_panel_views.values()]
- def panel_view_dicts(self) -> Dict[str, Dict]:
+ def panel_view_dicts(self) -> dict[str, dict]:
return {m.id: m.model_dump(mode="json") for m in self.panel_views()}
def panel_has_tool(self, tool: "Tool", panel_view_id: str) -> bool:
@@ -446,7 +441,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
integrated_panel_dict=None,
load_panel_dict: bool = True,
guid=None,
- index: Optional[int] = None,
+ index: int | None = None,
) -> None:
with self.app._toolbox_lock:
item = ensure_tool_conf_item(item)
@@ -497,7 +492,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
load_panel_dict=load_panel_dict,
)
- def get_shed_config_dict_by_filename(self, filename) -> Optional[DynamicToolConfDict]:
+ def get_shed_config_dict_by_filename(self, filename) -> DynamicToolConfDict | None:
filename = os.path.abspath(filename)
dynamic_tool_conf_paths = []
for shed_config_dict in self._dynamic_tool_confs:
@@ -551,7 +546,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
log.debug(f"Loading new tool panel section: {str(tool_section.name)}")
return tool_section
- def get_section_for_tool(self, tool) -> Union[Tuple[str, str], Tuple[None, None]]:
+ def get_section_for_tool(self, tool) -> tuple[str, str] | tuple[None, None]:
tool_id = tool.id
return self._tool_panel.get_section_for_tool_id(tool_id)
@@ -639,7 +634,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
log.debug(log_msg)
def _load_tool_panel_views(self) -> None:
- self._tool_panel_view_rendered: Dict[str, ToolPanelElements] = {}
+ self._tool_panel_view_rendered: dict[str, ToolPanelElements] = {}
registry = ToolBoxRegistryImpl(self)
for key, view in self._tool_panel_views.items():
self._tool_panel_view_rendered[key] = view.apply_view(self._integrated_tool_panel, registry)
@@ -722,34 +717,34 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
@overload
def get_tool(
self,
- tool_id: Optional[str] = None,
- tool_version: Optional[str] = None,
- tool_uuid: Optional[Union[UUID, str]] = None,
+ tool_id: str | None = None,
+ tool_version: str | None = None,
+ tool_uuid: UUID | str | None = None,
get_all_versions: Literal[False] = False,
- exact: Optional[bool] = False,
+ exact: bool | None = False,
user: Optional["User"] = None,
) -> Optional["Tool"]: ...
@overload
def get_tool(
self,
- tool_id: Optional[str] = None,
- tool_version: Optional[str] = None,
- tool_uuid: Optional[Union[UUID, str]] = None,
+ tool_id: str | None = None,
+ tool_version: str | None = None,
+ tool_uuid: UUID | str | None = None,
get_all_versions: Literal[True] = True,
- exact: Optional[bool] = False,
+ exact: bool | None = False,
user: Optional["User"] = None,
- ) -> List["Tool"]: ...
+ ) -> list["Tool"]: ...
def get_tool(
self,
- tool_id: Optional[str] = None,
- tool_version: Optional[str] = None,
- tool_uuid: Optional[Union[UUID, str]] = None,
- get_all_versions: Optional[bool] = False,
- exact: Optional[bool] = False,
+ tool_id: str | None = None,
+ tool_version: str | None = None,
+ tool_uuid: UUID | str | None = None,
+ get_all_versions: bool | None = False,
+ exact: bool | None = False,
user: Optional["User"] = None,
- ) -> Union[Optional["Tool"], List["Tool"]]:
+ ) -> Optional["Tool"] | list["Tool"]:
"""Attempt to locate a tool in the tool box. Note that `exact` only refers to the `tool_id`, not the `tool_version`."""
if tool_id is None and tool_uuid is None:
raise RequestParameterInvalidException("get_tool cannot be called with both tool_id and tool_uuid as None")
@@ -842,9 +837,9 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
def has_tool(
self,
- tool_id: Optional[str],
- tool_version: Optional[str] = None,
- tool_uuid: Optional[Union[UUID, str]] = None,
+ tool_id: str | None,
+ tool_version: str | None = None,
+ tool_uuid: UUID | str | None = None,
exact: bool = False,
user: Optional["User"] = None,
):
@@ -852,10 +847,10 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
self.get_tool(tool_id, tool_version=tool_version, tool_uuid=tool_uuid, exact=exact, user=user) is not None
)
- def get_unprivileged_tool(self, user: "User", tool_uuid: Union[UUID, str]) -> Optional["Tool"]:
+ def get_unprivileged_tool(self, user: "User", tool_uuid: UUID | str) -> Optional["Tool"]:
return None
- def get_unprivileged_tool_or_none(self, user: "User", tool_uuid: Union[UUID, str]) -> Optional["Tool"]:
+ def get_unprivileged_tool_or_none(self, user: "User", tool_uuid: UUID | str) -> Optional["Tool"]:
return None
def is_missing_shed_tool(self, tool_id: str) -> bool:
@@ -871,8 +866,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
def get_loaded_tools_by_lineage(self, tool_id: str) -> list:
"""Get all loaded tools associated by lineage to the tool whose id is tool_id."""
- tool_lineage = self._lineage_map.get(tool_id)
- if tool_lineage:
+ if tool_lineage := self._lineage_map.get(tool_id):
lineage_tool_versions = tool_lineage.get_versions()
available_tool_versions = []
for lineage_tool_version in lineage_tool_versions:
@@ -889,7 +883,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
def tools(self):
return self._tools_by_id.copy().items()
- def dynamic_confs(self, include_migrated_tool_conf=False) -> List[DynamicToolConfDict]:
+ def dynamic_confs(self, include_migrated_tool_conf=False) -> list[DynamicToolConfDict]:
confs = []
for dynamic_tool_conf_dict in self._dynamic_tool_confs:
dynamic_tool_conf_filename = dynamic_tool_conf_dict["config_filename"]
@@ -931,7 +925,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
tool_path,
load_panel_dict: bool,
guid=None,
- index: Optional[int] = None,
+ index: int | None = None,
) -> None:
try:
path_template = item.get("file")
@@ -1014,7 +1008,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
# so if we load a tool it needs to be at a path that contains `installed_changeset_revision`.
path_to_installed_changeset_revision = os.path.join(tool_shed, "repos", repository_owner, repository_name)
if path_to_installed_changeset_revision in path:
- installed_changeset_revision: Optional[str] = path[
+ installed_changeset_revision: str | None = path[
path.index(path_to_installed_changeset_revision) + len(path_to_installed_changeset_revision) :
].split(os.path.sep)[1]
else:
@@ -1024,7 +1018,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
installed_changeset_revision_elem = elem.find("changeset_revision")
assert installed_changeset_revision_elem is not None
installed_changeset_revision = installed_changeset_revision_elem.text
- repository: Union[ToolConfRepository, ToolShedRepository] = self._get_tool_shed_repository(
+ repository: ToolConfRepository | ToolShedRepository = self._get_tool_shed_repository(
tool_shed=tool_shed,
name=repository_name,
owner=repository_owner,
@@ -1059,7 +1053,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
@abc.abstractmethod
def _get_tool_shed_repository(
- self, tool_shed: str, name: str, owner: str, installed_changeset_revision: Optional[str]
+ self, tool_shed: str, name: str, owner: str, installed_changeset_revision: str | None
) -> "ToolShedRepository":
# Abstract class doesn't have a dependency on the database, for full Tool Shed
# support the actual Galaxy ToolBox implements this method and returns a Tool Shed repository.
@@ -1080,7 +1074,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
self.__add_tool_to_tool_panel(tool, panel_dict)
def _load_workflow_tag_set(
- self, item, panel_dict, integrated_panel_dict, load_panel_dict: bool, index: Optional[int] = None
+ self, item, panel_dict, integrated_panel_dict, load_panel_dict: bool, index: int | None = None
) -> None:
try:
# TODO: should id be encoded?
@@ -1096,7 +1090,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
log.exception("Error loading workflow: %s", workflow_id)
def _load_label_tag_set(
- self, item, panel_dict, integrated_panel_dict, load_panel_dict: bool, index: Optional[int] = None
+ self, item, panel_dict, integrated_panel_dict, load_panel_dict: bool, index: int | None = None
) -> None:
label = ToolSectionLabel(item)
key = f"label_{label.id}"
@@ -1104,7 +1098,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
panel_dict[key] = label
integrated_panel_dict.update_or_append(index, key, label)
- def _load_section_tag_set(self, item, tool_path, load_panel_dict: bool, index: Optional[int] = None) -> None:
+ def _load_section_tag_set(self, item, tool_path, load_panel_dict: bool, index: int | None = None) -> None:
key = item.get("id")
if key in self._tool_panel:
section = self._tool_panel[key]
@@ -1162,7 +1156,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
recursive: bool,
force_watch: bool = False,
) -> None:
- def quick_load(tool_file: "StrPath", async_load: bool = True) -> Union[str, None]:
+ def quick_load(tool_file: "StrPath", async_load: bool = True) -> str | None:
if not self._looks_like_a_tool(str(tool_file)):
return None
try:
@@ -1214,7 +1208,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
) -> "Tool":
"""Load a single tool from the file named by `config_file` and return an instance of `Tool`."""
# Parse XML configuration file and get the root element
- tool: Optional[Tool] = None
+ tool: Tool | None = None
if use_cached:
tool = self.load_tool_from_cache(config_file)
if not tool or guid and guid != tool.guid:
@@ -1246,12 +1240,12 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
[self._tool_config_watcher.watch_file(macro_path) for macro_path in tool._macro_paths]
def add_tool_to_cache(self, tool: "Tool", config_file: "StrPath") -> None:
- tool_cache: Optional[ToolCache] = getattr(self.app, "tool_cache", None)
+ tool_cache: ToolCache | None = getattr(self.app, "tool_cache", None)
if tool_cache:
tool_cache.cache_tool(config_file, tool)
def load_tool_from_cache(self, config_file: "StrPath", recover_tool: bool = False) -> Union["Tool", None]:
- tool_cache: Optional[ToolCache] = getattr(self.app, "tool_cache", None)
+ tool_cache: ToolCache | None = getattr(self.app, "tool_cache", None)
tool = None
if tool_cache:
if recover_tool:
@@ -1293,13 +1287,12 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
# tool before re-registering. Invalidating unconditionally keeps the
# to_dict + curated-id-set caches consistent with the live tool.
self._invalidate_tool_caches(tool_id)
- old_id = tool.old_id
- if old_id:
+ if old_id := tool.old_id:
if old_id not in self._tools_by_old_id:
self._tools_by_old_id[old_id] = []
self._tools_by_old_id[old_id].append(tool)
- def _invalidate_tool_caches(self, tool_id: Optional[str] = None) -> None:
+ def _invalidate_tool_caches(self, tool_id: str | None = None) -> None:
"""Drop cached `to_dict` payloads and curated/EDAM id sets.
Called whenever a tool is registered, reloaded, or removed so callers don't
@@ -1315,7 +1308,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
self._tool_edam_operations = None
self._tool_edam_topics = None
- def _collect_tool_attribute_set(self, attribute: str) -> FrozenSet[str]:
+ def _collect_tool_attribute_set(self, attribute: str) -> frozenset[str]:
values: set = set()
for _, tool in self.tools():
attr_values = getattr(tool, attribute, None) or ()
@@ -1323,21 +1316,21 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
return frozenset(values)
@property
- def curated_tool_tags(self) -> FrozenSet[str]:
+ def curated_tool_tags(self) -> frozenset[str]:
"""Set of curated tag names known to the loaded tools (lazy, cached)."""
if self._curated_tool_tags is None:
self._curated_tool_tags = self._collect_tool_attribute_set("tool_tags")
return self._curated_tool_tags
@property
- def tool_edam_operations(self) -> FrozenSet[str]:
+ def tool_edam_operations(self) -> frozenset[str]:
"""Set of EDAM operation ids referenced by loaded tools (lazy, cached)."""
if self._tool_edam_operations is None:
self._tool_edam_operations = self._collect_tool_attribute_set("edam_operations")
return self._tool_edam_operations
@property
- def tool_edam_topics(self) -> FrozenSet[str]:
+ def tool_edam_topics(self) -> frozenset[str]:
"""Set of EDAM topic ids referenced by loaded tools (lazy, cached)."""
if self._tool_edam_topics is None:
self._tool_edam_topics = self._collect_tool_attribute_set("edam_topics")
@@ -1357,12 +1350,12 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
tool = self._tools_by_id[tool_id]
return tool.to_archive()
- def reload_tool_by_id(self, tool_id: str) -> Tuple[Union[str, Dict[str, str]], str]:
+ def reload_tool_by_id(self, tool_id: str) -> tuple[str | dict[str, str], str]:
"""
Attempt to reload the tool identified by 'tool_id', if successful
replace the old tool.
"""
- message: Union[str, Dict[str, str]]
+ message: str | dict[str, str]
if tool_id not in self._tools_by_id:
message = f"No tool with id '{escape(tool_id)}'."
status = "error"
@@ -1406,7 +1399,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
self._invalidate_tool_caches(tool_id)
if tool.old_id:
self._tools_by_old_id[tool.old_id].remove(tool)
- tool_cache: Optional[ToolCache] = getattr(self.app, "tool_cache", None)
+ tool_cache: ToolCache | None = getattr(self.app, "tool_cache", None)
if tool_cache:
tool_cache.expire_tool(tool_id)
if remove_from_panel:
@@ -1472,7 +1465,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
if elt:
yield elt
- def get_tool_to_dict(self, trans, tool: "Tool", tool_help: bool = False) -> Dict[str, Any]:
+ def get_tool_to_dict(self, trans, tool: "Tool", tool_help: bool = False) -> dict[str, Any]:
"""Return tool's to_dict.
Use cache if present, store to cache otherwise.
Note: The cached tool's to_dict is specific to the calls from toolbox.
@@ -1500,9 +1493,9 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
trans,
in_panel: bool = True,
tool_help: bool = False,
- view: Optional[str] = None,
+ view: str | None = None,
**kwds,
- ) -> List[Dict[str, Any]]:
+ ) -> list[dict[str, Any]]:
"""
Create a dictionary representation of the toolbox.
Uses primitive cache for toolbox-specific tool 'to_dict's.
@@ -1534,7 +1527,7 @@ class AbstractToolBox(ManagesIntegratedToolPanelMixin):
"""
if view == "default_panel_view":
view = self._default_panel_view(trans)
- view_contents: Dict[str, Dict] = {}
+ view_contents: dict[str, dict] = {}
panel_elts = self.tool_panel_contents(trans, view=view, **kwds)
for elt in panel_elts:
# Only use cache for objects that are Tools.
diff --git a/lib/galaxy/tool_util/toolbox/lineages/factory.py b/lib/galaxy/tool_util/toolbox/lineages/factory.py
index 1b32638180f..6154def6bf9 100644
--- a/lib/galaxy/tool_util/toolbox/lineages/factory.py
+++ b/lib/galaxy/tool_util/toolbox/lineages/factory.py
@@ -1,6 +1,4 @@
from typing import (
- Dict,
- Optional,
TYPE_CHECKING,
)
@@ -15,7 +13,7 @@ class LineageMap:
"""Map each unique tool id to a lineage object."""
def __init__(self, app):
- self.lineage_map: Dict[str, ToolLineage] = {}
+ self.lineage_map: dict[str, ToolLineage] = {}
self.app = app
def register(self, tool: "Tool") -> ToolLineage:
@@ -37,7 +35,7 @@ class LineageMap:
self.lineage_map[tool_id] = lineage
return self.lineage_map[tool_id]
- def get(self, tool_id: str) -> Optional[ToolLineage]:
+ def get(self, tool_id: str) -> ToolLineage | None:
"""
Get lineage for `tool_id`.
@@ -63,7 +61,7 @@ class LineageMap:
self.lineage_map[tool_id] = lineage
return self.lineage_map.get(tool_id)
- def _get_versionless(self, tool_id: str) -> Optional[ToolLineage]:
+ def _get_versionless(self, tool_id: str) -> ToolLineage | None:
versionless_tool_id = remove_version_from_guid(tool_id)
if not versionless_tool_id:
return None
diff --git a/lib/galaxy/tool_util/toolbox/lineages/interface.py b/lib/galaxy/tool_util/toolbox/lineages/interface.py
index 344a161c3ec..442e74e609d 100644
--- a/lib/galaxy/tool_util/toolbox/lineages/interface.py
+++ b/lib/galaxy/tool_util/toolbox/lineages/interface.py
@@ -1,8 +1,6 @@
import threading
from typing import (
Any,
- Dict,
- List,
TYPE_CHECKING,
)
@@ -33,7 +31,7 @@ class ToolLineageVersion:
"""
return self.version is None
- def to_dict(self) -> Dict[str, str]:
+ def to_dict(self) -> dict[str, str]:
return dict(
id=self.id,
version=self.version,
@@ -45,7 +43,7 @@ class ToolLineage:
determined solely by PEP 440 versioning scheme.
"""
- lineages_by_id: Dict[str, "ToolLineage"] = {}
+ lineages_by_id: dict[str, "ToolLineage"] = {}
lock = threading.Lock()
def __init__(self, tool_id: str) -> None:
@@ -53,7 +51,7 @@ class ToolLineage:
self.tool_versions = SortedSet(key=parse_version)
@property
- def tool_ids(self) -> List[str]:
+ def tool_ids(self) -> list[str]:
versionless_tool_id = remove_version_from_guid(self.tool_id)
tool_id = versionless_tool_id or self.tool_id
return [f"{tool_id}/{version}" for version in self.tool_versions]
@@ -73,7 +71,7 @@ class ToolLineage:
def register_version(self, tool_version: str) -> None:
self.tool_versions.add(tool_version)
- def get_versions(self) -> List[ToolLineageVersion]:
+ def get_versions(self) -> list[ToolLineageVersion]:
"""
Return an ordered list of lineages (ToolLineageVersion) in this
chain, from oldest to newest.
@@ -83,12 +81,12 @@ class ToolLineage:
for tool_id, tool_version in zip(self.tool_ids, self.tool_versions)
]
- def get_version_ids(self, reverse: bool = False) -> List[str]:
+ def get_version_ids(self, reverse: bool = False) -> list[str]:
if reverse:
return list(reversed(self.tool_ids))
return self.tool_ids
- def to_dict(self) -> Dict[str, Any]:
+ def to_dict(self) -> dict[str, Any]:
return dict(
tool_id=self.tool_id,
tool_versions=list(self.tool_versions),
diff --git a/lib/galaxy/tool_util/toolbox/panel.py b/lib/galaxy/tool_util/toolbox/panel.py
index b8d937080ab..bfdc53f5cfd 100644
--- a/lib/galaxy/tool_util/toolbox/panel.py
+++ b/lib/galaxy/tool_util/toolbox/panel.py
@@ -2,11 +2,7 @@ from abc import abstractmethod
from enum import Enum
from typing import (
Any,
- Dict,
- Optional,
- Tuple,
TYPE_CHECKING,
- Union,
)
from galaxy.util.dictifiable import UsesDictVisibleKeys
@@ -166,12 +162,12 @@ class ToolPanelElements(odict[str, Any], HasPanelItems):
used both by tool panel itself (normal and integrated) and its sections.
"""
- _section_by_tool: Dict[str, Tuple[str, str]] = {}
+ _section_by_tool: dict[str, tuple[str, str]] = {}
def record_section_for_tool_id(self, tool_id: str, key: str, val: str):
self._section_by_tool[tool_id] = (key, val)
- def get_section_for_tool_id(self, tool_id: str) -> Union[Tuple[str, str], Tuple[None, None]]:
+ def get_section_for_tool_id(self, tool_id: str) -> tuple[str, str] | tuple[None, None]:
if tool_id in self._section_by_tool:
return self._section_by_tool[tool_id]
return (None, None)
@@ -188,7 +184,7 @@ class ToolPanelElements(odict[str, Any], HasPanelItems):
break
def get_or_create_section(
- self, sec_id: str, sec_nm: str, description: Optional[str] = None, links: Optional[Dict[str, str]] = None
+ self, sec_id: str, sec_nm: str, description: str | None = None, links: dict[str, str] | None = None
) -> ToolSection:
if sec_id not in self:
section = ToolSection(
@@ -216,7 +212,7 @@ class ToolPanelElements(odict[str, Any], HasPanelItems):
else:
self.insert(index, key, value)
- def get_label(self, label: str) -> Optional[ToolSection]:
+ def get_label(self, label: str) -> ToolSection | None:
for element in self.values():
if isinstance(element, ToolSection) and element.name == label:
return element
@@ -233,7 +229,7 @@ class ToolPanelElements(odict[str, Any], HasPanelItems):
del self[previous_key]
self.insert(index, new_key, tool)
- def index_of_tool_id(self, tool_id: str) -> Optional[int]:
+ def index_of_tool_id(self, tool_id: str) -> int | None:
query_key = f"tool_{tool_id}"
for index, target_key in enumerate(self.keys()):
if query_key == target_key:
@@ -275,7 +271,7 @@ class ToolPanelElements(odict[str, Any], HasPanelItems):
if isinstance(item, ToolSection):
yield (key, item)
- def closest_section(self, target_section_id: Optional[str], target_section_name: Optional[str]):
+ def closest_section(self, target_section_id: str | None, target_section_name: str | None):
for section_id, section in self.walk_sections():
if section_id == target_section_id:
return section
diff --git a/lib/galaxy/tool_util/toolbox/views/definitions.py b/lib/galaxy/tool_util/toolbox/views/definitions.py
index bfb9fe9cc42..bff05ecc356 100644
--- a/lib/galaxy/tool_util/toolbox/views/definitions.py
+++ b/lib/galaxy/tool_util/toolbox/views/definitions.py
@@ -2,9 +2,7 @@ from enum import Enum
from typing import (
Any,
cast,
- List,
- Optional,
- Union,
+ Literal,
)
from pydantic import (
@@ -12,9 +10,6 @@ from pydantic import (
ConfigDict,
Field,
)
-from typing_extensions import (
- Literal,
-)
class StaticToolBoxViewTypeEnum(str, Enum):
@@ -33,15 +28,11 @@ class ExcludeToolRegex(BaseModel):
class ExcludeTypes(BaseModel):
- types: List[str]
+ types: list[str]
-Exclusions = Union[
- ExcludeTool,
- ExcludeToolRegex,
- ExcludeTypes,
-]
-OptionalExclusionList = Optional[List[Exclusions]]
+Exclusions = ExcludeTool | ExcludeToolRegex | ExcludeTypes
+OptionalExclusionList = list[Exclusions] | None
class Tool(BaseModel):
@@ -52,7 +43,7 @@ class Tool(BaseModel):
class Label(BaseModel):
content_type: Literal["label"] = Field(alias="type", default="label")
- id: Optional[str] = None
+ id: str | None = None
text: str
model_config = ConfigDict(populate_by_name=True)
@@ -74,26 +65,20 @@ class ItemsFrom(BaseModel):
excludes: OptionalExclusionList = None
-SectionContent = Union[
- Tool,
- Label,
- LabelShortcut,
- Workflow,
- ItemsFrom,
-]
+SectionContent = Tool | Label | LabelShortcut | Workflow | ItemsFrom
class HasItems:
- items: Optional[List[Any]]
+ items: list[Any] | None
@property
- def items_expanded(self) -> Optional[List["ExpandedRootContent"]]:
+ def items_expanded(self) -> list["ExpandedRootContent"] | None:
if self.items is None:
return None
# replace SectionAliases with individual SectionAlias objects
# replace LabelShortcuts with Labels
- items: List[ExpandedRootContent] = []
+ items: list[ExpandedRootContent] = []
for item in self.items:
item = cast(RootContent, item)
if isinstance(item, SectionAliases):
@@ -117,9 +102,9 @@ class HasItems:
class Section(BaseModel, HasItems):
content_type: Literal["section"] = Field(alias="type")
- id: Optional[str] = None
- name: Optional[str] = None
- items: Optional[List[SectionContent]] = None
+ id: str | None = None
+ name: str | None = None
+ items: list[SectionContent] | None = None
excludes: OptionalExclusionList = None
model_config = ConfigDict(populate_by_name=True)
@@ -132,37 +117,21 @@ class SectionAlias(BaseModel):
class SectionAliases(BaseModel):
content_type: Literal["section_aliases"] = "section_aliases"
- sections: List[str]
+ sections: list[str]
excludes: OptionalExclusionList = None
-RootContent = Union[
- Section,
- SectionAlias,
- SectionAliases,
- Tool,
- Label,
- LabelShortcut,
- Workflow,
- ItemsFrom,
-]
+RootContent = Section | SectionAlias | SectionAliases | Tool | Label | LabelShortcut | Workflow | ItemsFrom
-ExpandedRootContent = Union[
- Section,
- SectionAlias,
- Tool,
- Label,
- Workflow,
- ItemsFrom,
-]
+ExpandedRootContent = Section | SectionAlias | Tool | Label | Workflow | ItemsFrom
class StaticToolBoxView(BaseModel, HasItems):
id: str
name: str
- description: Optional[str] = None
+ description: str | None = None
view_type: StaticToolBoxViewTypeEnum = Field(alias="type")
- items: Optional[List[RootContent]] = None # if empty, use integrated tool panel
+ items: list[RootContent] | None = None # if empty, use integrated tool panel
excludes: OptionalExclusionList = None
@staticmethod
diff --git a/lib/galaxy/tool_util/toolbox/views/edam.py b/lib/galaxy/tool_util/toolbox/views/edam.py
index 3334de79d9a..383509276cd 100644
--- a/lib/galaxy/tool_util/toolbox/views/edam.py
+++ b/lib/galaxy/tool_util/toolbox/views/edam.py
@@ -1,10 +1,5 @@
import logging
from enum import Enum
-from typing import (
- Dict,
- List,
- Tuple,
-)
from galaxy.tool_util.edam_util import (
ROOT_OPERATION,
@@ -33,7 +28,7 @@ class EdamPanelMode(str, Enum):
class EdamToolPanelView(ToolPanelView):
- def __init__(self, edam: Dict[str, Dict], mode: EdamPanelMode = EdamPanelMode.merged):
+ def __init__(self, edam: dict[str, dict], mode: EdamPanelMode = EdamPanelMode.merged):
self.edam = edam
self.mode = mode
self.include_topics = mode in [EdamPanelMode.merged, EdamPanelMode.topics]
@@ -51,9 +46,9 @@ class EdamToolPanelView(ToolPanelView):
# topics = sorted(topics, key=lambda x: self.edam[x]['label'])
# Convert these to list of dicts, wherein we'll add our tools/etc.
- operations: Dict[str, Dict] = {x: {} for x in operations_list}
- topics: Dict[str, Dict] = {x: {} for x in topics_list}
- uncategorized: List[Tuple] = []
+ operations: dict[str, dict] = {x: {} for x in operations_list}
+ topics: dict[str, dict] = {x: {} for x in topics_list}
+ uncategorized: list[tuple] = []
for tool_id, key, val, val_name in walk_loaded_tools(base_tool_panel, toolbox_registry):
for term in self._get_edam_sec(val):
diff --git a/lib/galaxy/tool_util/toolbox/views/interface.py b/lib/galaxy/tool_util/toolbox/views/interface.py
index b8968cad6cd..e8d846b33ee 100644
--- a/lib/galaxy/tool_util/toolbox/views/interface.py
+++ b/lib/galaxy/tool_util/toolbox/views/interface.py
@@ -1,6 +1,5 @@
from abc import abstractmethod
from enum import Enum
-from typing import Optional
from pydantic import (
BaseModel,
@@ -30,7 +29,7 @@ class ToolPanelViewModel(BaseModel):
id: str
model_class: str
name: str
- description: Optional[str] = None
+ description: str | None = None
view_type: ToolPanelViewModelType
searchable: bool # Allow for more dynamic views that don't plug into fixed search indicies in the future...
model_config = ConfigDict(protected_namespaces=())
diff --git a/lib/galaxy/tool_util/toolbox/views/sources.py b/lib/galaxy/tool_util/toolbox/views/sources.py
index c78b7889a50..4e34eed0490 100644
--- a/lib/galaxy/tool_util/toolbox/views/sources.py
+++ b/lib/galaxy/tool_util/toolbox/views/sources.py
@@ -1,9 +1,5 @@
import logging
import os
-from typing import (
- Dict,
- List,
-)
import yaml
@@ -16,14 +12,14 @@ EXTENSIONS = [".yml", ".yaml", ".json"]
class StaticToolBoxViewSources:
- view_directories: List[str]
- view_dicts: List[Dict]
+ view_directories: list[str]
+ view_dicts: list[dict]
def __init__(self, view_directories=None, view_dicts=None):
self.view_directories = config_directories_from_setting(view_directories) or []
self.view_dicts = view_dicts or []
- def get_definitions(self) -> List[StaticToolBoxView]:
+ def get_definitions(self) -> list[StaticToolBoxView]:
view_definitions = []
for view_dict in self.view_dicts:
diff --git a/lib/galaxy/tool_util/toolbox/views/static.py b/lib/galaxy/tool_util/toolbox/views/static.py
index 7972cc84e83..fd73c9efb5a 100644
--- a/lib/galaxy/tool_util/toolbox/views/static.py
+++ b/lib/galaxy/tool_util/toolbox/views/static.py
@@ -1,6 +1,5 @@
import logging
import re
-from typing import Optional
from .definitions import (
ExcludeTool,
@@ -69,8 +68,7 @@ class StaticToolPanelView(ToolPanelView):
def apply_view(self, base_tool_panel: ToolPanelElements, toolbox_registry: ToolBoxRegistry) -> ToolPanelElements:
def apply_filter(definition, elems):
- excludes = self._all_excludes(definition)
- if excludes:
+ if excludes := self._all_excludes(definition):
elems.apply_filter(build_filter(excludes))
def definition_with_items_to_panel(definition, allow_sections: bool = True, items=None):
@@ -159,8 +157,7 @@ class StaticToolPanelView(ToolPanelView):
else:
raise AssertionError("Unknown static toolbox configuration element encountered.")
- excludes = self._all_excludes(definition)
- if excludes:
+ if excludes := self._all_excludes(definition):
new_panel.apply_filter(build_filter(excludes))
return new_panel
@@ -171,7 +168,7 @@ class StaticToolPanelView(ToolPanelView):
root_items = []
# No items found, use base tool panel and apply filters to that...
for _, panel_type, panel_value in base_tool_panel.panel_items_iter():
- item: Optional[ExpandedRootContent] = None
+ item: ExpandedRootContent | None = None
if panel_type == panel_item_types.TOOL:
item = Tool(
id=panel_value.id,
diff --git a/lib/galaxy/tool_util/unittest_utils/__init__.py b/lib/galaxy/tool_util/unittest_utils/__init__.py
index bbdafb1b523..9db10fe2c71 100644
--- a/lib/galaxy/tool_util/unittest_utils/__init__.py
+++ b/lib/galaxy/tool_util/unittest_utils/__init__.py
@@ -1,10 +1,5 @@
import os
-from typing import (
- Callable,
- Dict,
- Optional,
- Union,
-)
+from collections.abc import Callable
from unittest.mock import Mock
from galaxy.tool_util.parser.factory import get_tool_source
@@ -22,8 +17,8 @@ def mock_trans(has_user=True, is_admin=False):
return trans
-def t_data_downloader_for(content: Union[Dict[Optional[str], bytes], bytes]) -> Callable[[str], bytes]:
- def get_content(filename: Optional[str]) -> bytes:
+def t_data_downloader_for(content: dict[str | None, bytes] | bytes) -> Callable[[str], bytes]:
+ def get_content(filename: str | None) -> bytes:
if isinstance(content, dict):
assert filename in content, f"failed to find {filename} in {content}"
return content[filename]
diff --git a/lib/galaxy/tool_util/unittest_utils/parameters.py b/lib/galaxy/tool_util/unittest_utils/parameters.py
index ecd7d500ee5..8496e0b89c6 100644
--- a/lib/galaxy/tool_util/unittest_utils/parameters.py
+++ b/lib/galaxy/tool_util/unittest_utils/parameters.py
@@ -15,7 +15,6 @@ from . import functional_test_tool_path
class ParameterBundle(ToolParameterBundle):
-
def __init__(self, parameter: ToolParameterT):
self.parameters = [parameter]
diff --git a/lib/galaxy/tool_util/upgrade/__init__.py b/lib/galaxy/tool_util/upgrade/__init__.py
index 00605b13c2f..71075a988ed 100644
--- a/lib/galaxy/tool_util/upgrade/__init__.py
+++ b/lib/galaxy/tool_util/upgrade/__init__.py
@@ -12,14 +12,10 @@ from json import loads
from typing import (
Any,
cast,
- Dict,
- List,
- Optional,
- Type,
+ Literal,
)
from typing_extensions import (
- Literal,
NotRequired,
TypedDict,
)
@@ -47,7 +43,7 @@ class AdviceCode(TypedDict):
upgrade_codes_json = resource_string(__name__, "upgrade_codes.json")
-upgrade_codes_by_name: Dict[str, AdviceCode] = {}
+upgrade_codes_by_name: dict[str, AdviceCode] = {}
for name, upgrade_object in loads(upgrade_codes_json).items():
upgrade_object["name"] = name
@@ -56,14 +52,14 @@ for name, upgrade_object in loads(upgrade_codes_json).items():
class Advice:
advice_code: AdviceCode
- message: Optional[str]
+ message: str | None
- def __init__(self, advice_code: AdviceCode, message: Optional[str]):
+ def __init__(self, advice_code: AdviceCode, message: str | None):
self.advice_code = advice_code
self.message = message
@property
- def url(self) -> Optional[str]:
+ def url(self) -> str | None:
return self.advice_code.get("url")
@property
@@ -78,23 +74,23 @@ class Advice:
def advice_code_message(self) -> str:
return self.advice_code["message"]
- def to_dict(self) -> Dict[str, Any]:
- as_dict = cast(Dict[str, Any], self.advice_code.copy())
+ def to_dict(self) -> dict[str, Any]:
+ as_dict = cast(dict[str, Any], self.advice_code.copy())
as_dict["advice_code_message"] = self.advice_code_message
as_dict["message"] = self.message
return as_dict
class AdviceCollection:
- _advice: List[Advice]
+ _advice: list[Advice]
def __init__(self):
self._advice = []
- def add(self, code: str, message: Optional[str] = None):
+ def add(self, code: str, message: str | None = None):
self._advice.append(Advice(upgrade_codes_by_name[code], message))
- def to_list(self) -> List[Advice]:
+ def to_list(self) -> list[Advice]:
return self._advice
@@ -202,8 +198,7 @@ class ProfileMigration20_09(ProfileMigration):
if output_collection.get("element_tests"):
advice_collection.add("20_09_consider_output_collection_order")
- command_el = tool_source._command_el
- if command_el is not None:
+ if (command_el := tool_source._command_el) is not None:
strict = command_el.get("strict", None)
if strict is None:
advice_collection.add("20_09_consider_set_e")
@@ -266,7 +261,7 @@ class ProfileMigration24_2(ProfileMigration):
advice_collection.add("24_2_fix_test_case_validation", str(result.validation_error))
-profile_migrations: List[Type[ProfileMigration]] = [
+profile_migrations: list[type[ProfileMigration]] = [
ProfileMigration16_04,
ProfileMigration17_09,
ProfileMigration18_01,
@@ -282,7 +277,7 @@ profile_migrations: List[Type[ProfileMigration]] = [
latest_supported_version = "24.2"
-def advise_on_upgrade(xml_file: str, to_version: Optional[str] = None) -> List[Advice]:
+def advise_on_upgrade(xml_file: str, to_version: str | None = None) -> list[Advice]:
to_version = to_version or latest_supported_version
tool_source = _xml_tool_source(xml_file)
initial_version = tool_source.parse_profile()
@@ -315,5 +310,5 @@ def _has_matching_xpath(tool_source: XmlToolSource, xpath: str) -> bool:
return tool_source.xml_tree.find(xpath) is not None
-def _find_all(tool_source: XmlToolSource, xpath: str) -> List[Element]:
- return cast(List[Element], tool_source.xml_tree.findall(".//data[@from_work_dir]") or [])
+def _find_all(tool_source: XmlToolSource, xpath: str) -> list[Element]:
+ return cast(list[Element], tool_source.xml_tree.findall(".//data[@from_work_dir]") or [])
diff --git a/lib/galaxy/tool_util/upgrade/script.py b/lib/galaxy/tool_util/upgrade/script.py
index 2778fc40c48..18cdd2af96a 100755
--- a/lib/galaxy/tool_util/upgrade/script.py
+++ b/lib/galaxy/tool_util/upgrade/script.py
@@ -7,7 +7,6 @@ from textwrap import (
indent,
wrap,
)
-from typing import List
from galaxy.tool_util.upgrade import (
Advice,
@@ -68,7 +67,7 @@ def _print_advice(advice: Advice):
print(f" More information at {url}")
-def _print_advice_list(advice_list: List[Advice]):
+def _print_advice_list(advice_list: list[Advice]):
for advice in advice_list:
_print_advice(advice)
diff --git a/lib/galaxy/tool_util/verify/__init__.py b/lib/galaxy/tool_util/verify/__init__.py
index 6420c3650a1..208ae6e8f79 100644
--- a/lib/galaxy/tool_util/verify/__init__.py
+++ b/lib/galaxy/tool_util/verify/__init__.py
@@ -11,12 +11,9 @@ import os.path
import re
import shutil
import tempfile
+from collections.abc import Callable
from typing import (
Any,
- Callable,
- Dict,
- List,
- Optional,
TYPE_CHECKING,
)
@@ -61,19 +58,19 @@ if TYPE_CHECKING:
log = logging.getLogger(__name__)
DEFAULT_TEST_DATA_RESOLVER = TestDataResolver()
-GetFilenameT = Optional[Callable[[str], str]]
-GetLocationT = Optional[Callable[[str], str]]
+GetFilenameT = Callable[[str], str] | None
+GetLocationT = Callable[[str], str] | None
def verify(
item_label: str,
output_content: bytes,
- attributes: Optional[Dict[str, Any]],
- filename: Optional[str] = None,
- get_filecontent: Optional[Callable[[str], bytes]] = None,
+ attributes: dict[str, Any] | None,
+ filename: str | None = None,
+ get_filecontent: Callable[[str], bytes] | None = None,
get_filename: GetFilenameT = None,
- keep_outputs_dir: Optional[str] = None,
- verify_extra_files: Optional[Callable] = None,
+ keep_outputs_dir: str | None = None,
+ verify_extra_files: Callable | None = None,
mode="file",
):
"""Verify the content of a test output using test definitions described by attributes.
@@ -257,8 +254,7 @@ def _verify_checksum(data, checksum_type, expected_checksum_value):
h = hashlib.new(checksum_type)
h.update(data)
- actual_checksum_value = h.hexdigest()
- if expected_checksum_value != actual_checksum_value:
+ if expected_checksum_value != (actual_checksum_value := h.hexdigest()):
template = "Output checksum [%s] does not match expected [%s] (using hash algorithm %s)."
message = template % (actual_checksum_value, expected_checksum_value, checksum_type)
raise AssertionError(message)
@@ -412,7 +408,6 @@ def files_re_match(file1, file2, attributes=None):
if attributes.get("sort", False):
history_data.sort()
local_file.sort()
- lines_diff = int(attributes.get("lines_diff", 0))
line_diff_count = 0
diffs = []
for regex_line, data_line in zip(local_file, history_data):
@@ -421,7 +416,7 @@ def files_re_match(file1, file2, attributes=None):
if not re.match(regex_line, data_line):
line_diff_count += 1
diffs.append(f"Regular Expression: {regex_line}, Data file: {data_line}\n")
- if line_diff_count > lines_diff:
+ if line_diff_count > (lines_diff := int(attributes.get("lines_diff", 0))):
raise AssertionError(
"Regular expression did not match data file (allowed variants={}):\n{}".format(lines_diff, "".join(diffs))
)
@@ -487,10 +482,10 @@ def _singleobject_intersection_over_union(
def _multiobject_intersection_over_union(
mask1: "numpy.typing.NDArray",
mask2: "numpy.typing.NDArray",
- pin_labels: Optional[List[int]] = None,
+ pin_labels: list[int] | None = None,
repeat_reverse: bool = True,
-) -> List["numpy.floating"]:
- iou_list: List[numpy.floating] = []
+) -> list["numpy.floating"]:
+ iou_list: list[numpy.floating] = []
for label1 in numpy.unique(mask1):
cc1 = mask1 == label1
@@ -501,7 +496,7 @@ def _multiobject_intersection_over_union(
# Otherwise, use the object with the largest IoU value, excluding the pinned labels.
else:
- cc1_iou_list: List[numpy.floating] = []
+ cc1_iou_list: list[numpy.floating] = []
for label2 in numpy.unique(mask2[cc1]):
if pin_labels is not None and label2 in pin_labels:
continue
@@ -516,7 +511,7 @@ def _multiobject_intersection_over_union(
def intersection_over_union(
- mask1: "numpy.typing.NDArray", mask2: "numpy.typing.NDArray", pin_labels: Optional[List[int]] = None
+ mask1: "numpy.typing.NDArray", mask2: "numpy.typing.NDArray", pin_labels: list[int] | None = None
) -> "numpy.floating":
"""Compute the intersection over union (IoU) for the objects in two masks containing labels.
@@ -539,7 +534,7 @@ def intersection_over_union(
return min(_multiobject_intersection_over_union(mask1, mask2, pin_labels)) # type: ignore[type-var, unused-ignore] # https://github.com/python/typeshed/issues/12562
-def _parse_label_list(label_list_str: Optional[str]) -> List[int]:
+def _parse_label_list(label_list_str: str | None) -> list[int]:
if label_list_str is None:
return []
else:
@@ -547,7 +542,7 @@ def _parse_label_list(label_list_str: Optional[str]) -> List[int]:
def get_image_metric(
- attributes: Dict[str, Any],
+ attributes: dict[str, Any],
) -> Callable[["numpy.typing.NDArray", "numpy.typing.NDArray"], "numpy.floating"]:
metric_name = attributes.get("metric", DEFAULT_METRIC)
pin_labels = _parse_label_list(attributes.get("pin_labels", DEFAULT_PIN_LABELS))
@@ -582,7 +577,7 @@ def _load_image(filepath: str) -> "numpy.typing.NDArray":
return arr
-def files_image_diff(file1: str, file2: str, attributes: Optional[Dict[str, Any]] = None) -> None:
+def files_image_diff(file1: str, file2: str, attributes: dict[str, Any] | None = None) -> None:
"""Check the pixel data of 2 image files for differences."""
attributes = attributes or {}
@@ -602,8 +597,7 @@ def files_image_diff(file1: str, file2: str, attributes: Optional[Dict[str, Any]
arr2 = arr2.astype(numpy.uint8)
distance = get_image_metric(attributes)(arr1, arr2)
- distance_eps = attributes.get("eps", DEFAULT_EPS)
- if distance > distance_eps:
+ if distance > (distance_eps := attributes.get("eps", DEFAULT_EPS)):
raise AssertionError(f"Image difference {distance} exceeds eps={distance_eps}.")
@@ -618,7 +612,7 @@ def verify_file_path_against_dict(
path: str,
output_content: bytes,
test_properties,
- test_data_target_dir: Optional[str] = None,
+ test_data_target_dir: str | None = None,
) -> None:
with open(path, "rb") as f:
output_content = f.read()
@@ -634,9 +628,9 @@ def verify_file_contents_against_dict(
item_label: str,
output_content: bytes,
test_properties,
- test_data_target_dir: Optional[str] = None,
+ test_data_target_dir: str | None = None,
) -> None:
- expected_file: Optional[str] = None
+ expected_file: str | None = None
if isinstance(test_properties, dict):
# Support Galaxy-like file location (using "file") or CWL-like ("path" or "location").
expected_file = test_properties.get("file", None)
@@ -671,12 +665,12 @@ def verify_file_contents_against_dict(
def verify_job_metadata(
- job_stdio: Dict[str, Any],
- expect_exit_code: Optional[int] = None,
- stdout_assertions: Optional[list] = None,
- stderr_assertions: Optional[list] = None,
- command_assertions: Optional[list] = None,
- command_version_assertions: Optional[list] = None,
+ job_stdio: dict[str, Any],
+ expect_exit_code: int | None = None,
+ stdout_assertions: list | None = None,
+ stderr_assertions: list | None = None,
+ command_assertions: list | None = None,
+ command_version_assertions: list | None = None,
) -> None:
"""Verify job exit code, stdout/stderr, and command metadata.
diff --git a/lib/galaxy/tool_util/verify/_types.py b/lib/galaxy/tool_util/verify/_types.py
index 8ba8ec397d2..d7a03f1b65d 100644
--- a/lib/galaxy/tool_util/verify/_types.py
+++ b/lib/galaxy/tool_util/verify/_types.py
@@ -2,14 +2,10 @@
from typing import (
Any,
- Dict,
- List,
- Optional,
- Tuple,
+ Literal,
)
from typing_extensions import (
- Literal,
NotRequired,
TypedDict,
)
@@ -25,45 +21,45 @@ from galaxy.tool_util_models.testing_types import (
# legacy inputs for working with POST /api/tools
# + inputs that have been processed with parse.py and expanded out
-ExpandedToolInputs = Dict[str, Any]
+ExpandedToolInputs = dict[str, Any]
# + ExpandedToolInputs where any model objects have been json-ified with to_dict()
-ExpandedToolInputsJsonified = Dict[str, Any]
+ExpandedToolInputsJsonified = dict[str, Any]
# modern inputs for working with POST /api/jobs*
-RawTestToolRequest = Dict[str, Any]
+RawTestToolRequest = dict[str, Any]
-ExtraFileInfoDictT = Dict[str, Any]
-RequiredFileTuple = Tuple[str, ExtraFileInfoDictT]
-RequiredFilesT = List[RequiredFileTuple]
-RequiredDataTablesT = List[str]
-RequiredLocFileT = List[str]
+ExtraFileInfoDictT = dict[str, Any]
+RequiredFileTuple = tuple[str, ExtraFileInfoDictT]
+RequiredFilesT = list[RequiredFileTuple]
+RequiredDataTablesT = list[str]
+RequiredLocFileT = list[str]
ValueStateRepresentationT = Literal["test_case_xml", "test_case_json"]
class ToolTestDescriptionDict(TypedDict):
tool_id: str
- tool_version: Optional[str]
+ tool_version: str | None
name: str
test_index: int
inputs: ExpandedToolInputsJsonified
- request: NotRequired[Optional[Dict[str, Any]]]
- request_schema: NotRequired[Optional[Dict[str, Any]]]
+ request: NotRequired[dict[str, Any] | None]
+ request_schema: NotRequired[dict[str, Any] | None]
outputs: ToolSourceTestOutputs
- output_collections: List[TestSourceTestOutputColllection]
- stdout: Optional[AssertionList]
- stderr: Optional[AssertionList]
- expect_exit_code: Optional[int]
+ output_collections: list[TestSourceTestOutputColllection]
+ stdout: AssertionList | None
+ stderr: AssertionList | None
+ expect_exit_code: int | None
expect_failure: bool
expect_test_failure: bool
- num_outputs: Optional[int]
- command_line: Optional[AssertionList]
- command_version: Optional[AssertionList]
- required_files: List[Any]
- required_data_tables: List[Any]
- required_loc_files: List[str]
+ num_outputs: int | None
+ command_line: AssertionList | None
+ command_version: AssertionList | None
+ required_files: list[Any]
+ required_data_tables: list[Any]
+ required_loc_files: list[str]
error: bool
- exception: Optional[str]
- request_unavailable_reason: NotRequired[Optional[str]]
- maxseconds: NotRequired[Optional[int]]
+ exception: str | None
+ request_unavailable_reason: NotRequired[str | None]
+ maxseconds: NotRequired[int | None]
value_state_representation: NotRequired[ValueStateRepresentationT]
- credentials: NotRequired[Optional[List[DirectCredential]]]
+ credentials: NotRequired[list[DirectCredential] | None]
diff --git a/lib/galaxy/tool_util/verify/asserts/__init__.py b/lib/galaxy/tool_util/verify/asserts/__init__.py
index 532692c6198..d17af330dbc 100644
--- a/lib/galaxy/tool_util/verify/asserts/__init__.py
+++ b/lib/galaxy/tool_util/verify/asserts/__init__.py
@@ -1,15 +1,11 @@
import logging
import sys
+from collections.abc import Callable
from inspect import (
getfullargspec,
getmembers,
)
from tempfile import NamedTemporaryFile
-from typing import (
- Callable,
- Dict,
- Tuple,
-)
from galaxy.util import unicodify
from galaxy.util.compression_utils import get_fileobj
@@ -18,7 +14,7 @@ log = logging.getLogger(__name__)
assertion_module_names = ["text", "tabular", "xml", "json", "hdf5", "archive", "size", "image"]
-assertion_module_and_functions: Dict[str, Tuple[str, Callable]] = {}
+assertion_module_and_functions: dict[str, tuple[str, Callable]] = {}
for assertion_module_name in assertion_module_names:
full_assertion_module_name = f"galaxy.tool_util.verify.asserts.{assertion_module_name}"
@@ -38,7 +34,7 @@ for assertion_module_name in assertion_module_names:
# create a new module of assertion functions, create the needed python
# source file "test/base/asserts/.py" and add
# to the list of assertion module names defined above.
-assertion_functions: Dict[str, Callable] = {k: v[1] for (k, v) in assertion_module_and_functions.items()}
+assertion_functions: dict[str, Callable] = {k: v[1] for (k, v) in assertion_module_and_functions.items()}
def verify_assertions(data: bytes, assertion_description_list: list, decompress: bool = False):
diff --git a/lib/galaxy/tool_util/verify/asserts/_types.py b/lib/galaxy/tool_util/verify/asserts/_types.py
index 4b2f601f9d5..0e51aee11fe 100644
--- a/lib/galaxy/tool_util/verify/asserts/_types.py
+++ b/lib/galaxy/tool_util/verify/asserts/_types.py
@@ -1,30 +1,27 @@
from typing import (
+ Annotated,
Any,
- List,
- Optional,
- Union,
)
from typing_extensions import (
- Annotated,
Protocol,
)
class AssertionParameter:
doc: str
- xml_type: Optional[str]
- json_type: Optional[str]
+ xml_type: str | None
+ json_type: str | None
deprecated: bool
- validators: List[str]
+ validators: list[str]
def __init__(
self,
- doc: Optional[str],
- xml_type: Optional[str] = None,
- json_type: Optional[str] = None,
+ doc: str | None,
+ xml_type: str | None = None,
+ json_type: str | None = None,
deprecated: bool = False,
- validators: Optional[List[str]] = None,
+ validators: list[str] | None = None,
):
self.doc = doc or ""
self.xml_type = xml_type
@@ -33,20 +30,19 @@ class AssertionParameter:
self.validators = validators or []
-XmlInt = Union[int, str]
-XmlFloat = Union[float, str]
-XmlBool = Union[bool, str]
+XmlInt = int | str
+XmlFloat = float | str
+XmlBool = bool | str
XmlRegex = str
-OptionalXmlInt = Optional[XmlInt]
-OptionalXmlFloat = Optional[XmlFloat]
-OptionalXmlBool = Optional[XmlBool]
+OptionalXmlInt = XmlInt | None
+OptionalXmlFloat = XmlFloat | None
+OptionalXmlBool = XmlBool | None
Output = Annotated[str, "The target output of a tool or workflow read as a UTF-8 string"]
OutputBytes = Annotated[bytes, "The target output of a tool or workflow read as raw Python 'bytes'"]
class VerifyAssertionsFunction(Protocol):
-
def __call__(self, data: bytes, assertion_description_list: list, decompress: bool = False):
"""Callback for recursirve functions."""
@@ -61,7 +57,7 @@ Negate = Annotated[
NEGATE_DEFAULT = False
N = Annotated[
- Optional[XmlInt], AssertionParameter("Desired number, can be suffixed by ``(k|M|G|T|P|E)i?``", xml_type="Bytes")
+ XmlInt | None, AssertionParameter("Desired number, can be suffixed by ``(k|M|G|T|P|E)i?``", xml_type="Bytes")
]
Delta = Annotated[
XmlInt,
@@ -70,11 +66,11 @@ Delta = Annotated[
),
]
Min = Annotated[
- Optional[XmlInt],
+ XmlInt | None,
AssertionParameter("Minimum number (default: -infinity), can be suffixed by ``(k|M|G|T|P|E)i?``", xml_type="Bytes"),
]
Max = Annotated[
- Optional[XmlInt],
+ XmlInt | None,
AssertionParameter("Maximum number (default: infinity), can be suffixed by ``(k|M|G|T|P|E)i?``", xml_type="Bytes"),
]
diff --git a/lib/galaxy/tool_util/verify/asserts/_util.py b/lib/galaxy/tool_util/verify/asserts/_util.py
index 2e3b604e98d..a133e5d7b60 100644
--- a/lib/galaxy/tool_util/verify/asserts/_util.py
+++ b/lib/galaxy/tool_util/verify/asserts/_util.py
@@ -1,9 +1,7 @@
+from collections.abc import Callable
from math import inf
from typing import (
- Callable,
- Optional,
TypeVar,
- Union,
)
from galaxy.util import asbool
@@ -12,11 +10,11 @@ from galaxy.util.bytesize import parse_bytesize
def _assert_number(
count: int,
- n: Optional[Union[int, str]],
- delta: Union[int, str],
- min: Optional[Union[int, str]],
- max: Optional[Union[int, str]],
- negate: Union[bool, str],
+ n: int | str | None,
+ delta: int | str,
+ min: int | str | None,
+ max: int | str | None,
+ negate: bool | str,
n_text: str,
min_max_text: str,
) -> None:
@@ -63,11 +61,11 @@ TextType = TypeVar("TextType")
def _assert_presence_number(
output: OutputType,
text: TextType,
- n: Optional[Union[int, str]],
- delta: Union[int, str],
- min: Optional[Union[int, str]],
- max: Optional[Union[int, str]],
- negate: Union[bool, str],
+ n: int | str | None,
+ delta: int | str,
+ min: int | str | None,
+ max: int | str | None,
+ negate: bool | str,
check_presence_foo: Callable[[OutputType, TextType], bool],
count_foo: Callable[[OutputType, TextType], int],
presence_text: str,
diff --git a/lib/galaxy/tool_util/verify/asserts/image.py b/lib/galaxy/tool_util/verify/asserts/image.py
index 4bbedbc324d..c0afd10e1e5 100644
--- a/lib/galaxy/tool_util/verify/asserts/image.py
+++ b/lib/galaxy/tool_util/verify/asserts/image.py
@@ -1,11 +1,7 @@
import io
from typing import (
Any,
- List,
- Optional,
- Tuple,
TYPE_CHECKING,
- Union,
)
from ._types import (
@@ -320,7 +316,7 @@ CenterOfMassEps = Annotated[
),
]
Labels = Annotated[
- Optional[Union[str, List[Union[float, int]]]],
+ str | list[float | int] | None,
AssertionParameter(
"List of labels, separated by a comma. Labels *not* on this list will be excluded from consideration. Cannot be used in combination with ``exclude_labels``.",
xml_type="xs:string",
@@ -328,7 +324,7 @@ Labels = Annotated[
),
]
ExcludeLabels = Annotated[
- Optional[Union[str, List[Union[float, int]]]],
+ str | list[float | int] | None,
AssertionParameter(
"List of labels to be excluded from consideration, separated by a comma. The primary usage of this attribute is to exclude the background of a label image. Cannot be used in combination with ``labels``.",
xml_type="xs:string",
@@ -376,10 +372,10 @@ MeanObjectSizeMax = Annotated[
def _assert_float(
actual: float,
label: str,
- tolerance: Union[float, str],
- expected: Optional[Union[float, str]] = None,
- range_min: Optional[Union[float, str]] = None,
- range_max: Optional[Union[float, str]] = None,
+ tolerance: float | str,
+ expected: float | str | None = None,
+ range_min: float | str | None = None,
+ range_max: float | str | None = None,
) -> None:
# Perform `tolerance` based check.
@@ -533,7 +529,7 @@ def assert_has_image_frames(
)
-def _compute_center_of_mass(im_arr: "numpy.typing.NDArray") -> Tuple[float, float]:
+def _compute_center_of_mass(im_arr: "numpy.typing.NDArray") -> tuple[float, float]:
im_arr_yx = im_arr.sum(axis=(0, 1, 4)) # Image axes are normalized like "TZYXC"
im_arr_yx = numpy.abs(im_arr_yx)
if im_arr_yx.sum() == 0:
@@ -560,9 +556,9 @@ def _swap_char(s: str, pos1: int, pos2: int) -> str:
def _get_image(
output_bytes: bytes,
- channel: Optional[Union[int, str]] = None,
- slice: Optional[Union[int, str]] = None,
- frame: Optional[Union[int, str]] = None,
+ channel: int | str | None = None,
+ slice: int | str | None = None,
+ frame: int | str | None = None,
) -> "numpy.typing.NDArray":
"""
Returns the output image with the axes ``TZYXC``, optionally restricted to a specific `channel`, `slice`,
@@ -731,19 +727,19 @@ def assert_has_image_center_of_mass(
def _get_image_labels(
output_bytes: bytes,
- channel: Optional[Union[int, str]] = None,
- slice: Optional[Union[int, str]] = None,
- frame: Optional[Union[int, str]] = None,
+ channel: int | str | None = None,
+ slice: int | str | None = None,
+ frame: int | str | None = None,
labels: Labels = None,
exclude_labels: ExcludeLabels = None,
-) -> Tuple["numpy.typing.NDArray", List[Any]]:
+) -> tuple["numpy.typing.NDArray", list[Any]]:
"""
Determines the unique labels in the output image or a specific channel.
"""
assert labels is None or exclude_labels is None
im_arr = _get_image(output_bytes, channel, slice, frame)
- def cast_label(label: str) -> Union[float, int]:
+ def cast_label(label: str) -> float | int:
label = label.strip()
if numpy.issubdtype(im_arr.dtype, numpy.integer):
return int(label)
@@ -758,7 +754,7 @@ def _get_image_labels(
raise AssertionError(f'Unsupported image label type: "{im_arr.dtype}"')
# Determine labels present in the image.
- present_labels: List[Any] = numpy.unique(im_arr).tolist()
+ present_labels: list[Any] = numpy.unique(im_arr).tolist()
# Apply filtering due to `labels` (keep only those).
if labels is None:
diff --git a/lib/galaxy/tool_util/verify/asserts/json.py b/lib/galaxy/tool_util/verify/asserts/json.py
index 1f67e6b4608..212aae270e2 100644
--- a/lib/galaxy/tool_util/verify/asserts/json.py
+++ b/lib/galaxy/tool_util/verify/asserts/json.py
@@ -1,7 +1,7 @@
import json
+from collections.abc import Callable
from typing import (
Any,
- Callable,
cast,
)
diff --git a/lib/galaxy/tool_util/verify/asserts/text.py b/lib/galaxy/tool_util/verify/asserts/text.py
index cda1969ffb3..00299db9d04 100644
--- a/lib/galaxy/tool_util/verify/asserts/text.py
+++ b/lib/galaxy/tool_util/verify/asserts/text.py
@@ -1,6 +1,5 @@
import re
-
-from typing_extensions import Annotated
+from typing import Annotated
from ._types import (
AssertionParameter,
diff --git a/lib/galaxy/tool_util/verify/asserts/xml.py b/lib/galaxy/tool_util/verify/asserts/xml.py
index 316c4e529c2..da39ff6de56 100644
--- a/lib/galaxy/tool_util/verify/asserts/xml.py
+++ b/lib/galaxy/tool_util/verify/asserts/xml.py
@@ -1,5 +1,4 @@
import re
-from typing import Optional
from lxml.etree import XMLSyntaxError
@@ -40,7 +39,7 @@ AttributeExpression = Annotated[
]
Attribute = Annotated[str, AssertionParameter("The XML attribute name to test against from the target XML element.")]
OptionalAttribute = Annotated[
- Optional[str], AssertionParameter("The XML attribute name to test against from the target XML element.")
+ str | None, AssertionParameter("The XML attribute name to test against from the target XML element.")
]
ElementText = Annotated[
str, AssertionParameter("The expected element text (body of the XML tag) to test against on the target XML element")
@@ -210,7 +209,7 @@ def assert_element_text(
def assert_xml_element(
output: Output,
path: Path,
- verify_assertions_function: Optional[VerifyAssertionsFunction] = None,
+ verify_assertions_function: VerifyAssertionsFunction | None = None,
children: ChildAssertions = None,
attribute: OptionalAttribute = None,
all: All = False,
diff --git a/lib/galaxy/tool_util/verify/codegen.py b/lib/galaxy/tool_util/verify/codegen.py
index 9e9b0b77eb2..ab8d621da57 100644
--- a/lib/galaxy/tool_util/verify/codegen.py
+++ b/lib/galaxy/tool_util/verify/codegen.py
@@ -7,21 +7,18 @@ import argparse
import inspect
import os
from shutil import move
+from types import UnionType
from typing import (
+ Annotated,
cast,
- List,
- Optional,
+ get_args,
+ get_origin,
+ Literal,
Union,
)
import lxml.etree as ET
from jinja2 import Environment
-from typing_extensions import (
- Annotated,
- get_args,
- get_origin,
- Literal,
-)
from galaxy.tool_util.verify.asserts import assertion_module_and_functions
from galaxy.tool_util.verify.asserts._types import AssertionParameter as AssertionParameterAnnotation
@@ -343,7 +340,6 @@ def rewrite_galaxy_xsd(assertions):
class AssertionParameter:
-
def __init__(self, name: str, type: str, default_value):
self.name = name
self.type = type
@@ -406,21 +402,19 @@ class AssertionParameter:
@property
def is_deprecated(self) -> bool:
- assertion_parameter = self._get_type_annotation()
- if assertion_parameter is not None:
+ if (assertion_parameter := self._get_type_annotation()) is not None:
return assertion_parameter.deprecated
return False
@property
- def validators(self) -> List[str]:
- assertion_parameter = self._get_type_annotation()
- if assertion_parameter is not None:
+ def validators(self) -> list[str]:
+ if (assertion_parameter := self._get_type_annotation()) is not None:
return assertion_parameter.validators
return []
- def _get_type_annotation(self) -> Optional[AssertionParameterAnnotation]:
+ def _get_type_annotation(self) -> AssertionParameterAnnotation | None:
target_type = self.type
if get_origin(target_type) is Annotated:
args = get_args(target_type)
@@ -447,7 +441,7 @@ def as_xml_type(target_type) -> str:
return assertion_parameter.xml_type
return as_xml_type(args[0])
- elif get_origin(target_type) is Union:
+ elif get_origin(target_type) in (Union, UnionType):
types = _non_optional_types(target_type)
if len(types) == 2:
non_str_types = [t for t in types if t is not str]
@@ -469,7 +463,7 @@ def as_type_str(target_type, strict=True):
return args[1].json_type
return as_type_str(args[0])
- elif get_origin(target_type) is Union:
+ elif get_origin(target_type) in (Union, UnionType):
is_optional = any(_is_none_type(t) for t in get_args(target_type))
types_as_str = ", ".join(map(as_type_str, _non_optional_types(target_type)))
union_type = f"typing.Union[{types_as_str}]"
@@ -490,12 +484,11 @@ def as_type_str(target_type, strict=True):
class Assertion:
-
def __init__(
self,
name: str,
docstring: str,
- parameters: List[AssertionParameter],
+ parameters: list[AssertionParameter],
children: Children,
module_and_function: str,
):
diff --git a/lib/galaxy/tool_util/verify/interactor.py b/lib/galaxy/tool_util/verify/interactor.py
index fe0a569533d..d42bbbfef81 100644
--- a/lib/galaxy/tool_util/verify/interactor.py
+++ b/lib/galaxy/tool_util/verify/interactor.py
@@ -10,26 +10,23 @@ import time
import traceback
import urllib.parse
import zipfile
+from collections.abc import (
+ Callable,
+ Generator,
+)
from json import dumps
from logging import getLogger
from typing import (
Any,
- Callable,
cast,
- Dict,
- Generator,
- List,
+ Literal,
NamedTuple,
- Optional,
- Tuple,
- Union,
)
from packaging.version import Version
from requests import Response
from requests.cookies import RequestsCookieJar
from typing_extensions import (
- Literal,
NotRequired,
Protocol,
TypedDict,
@@ -124,30 +121,30 @@ class OutputsDict(dict):
return super().__getitem__(item)
-JobDataT = Dict[str, Any]
+JobDataT = dict[str, Any]
JobDataCallbackT = Callable[[JobDataT], None]
class ValidToolTestDict(TypedDict):
inputs: ExpandedToolInputs
- request: NotRequired[Optional[RawTestToolRequest]]
- request_schema: NotRequired[Optional[Dict[str, Any]]]
- request_unavailable_reason: NotRequired[Optional[str]]
+ request: NotRequired[RawTestToolRequest | None]
+ request_schema: NotRequired[dict[str, Any] | None]
+ request_unavailable_reason: NotRequired[str | None]
outputs: ToolSourceTestOutputs
- output_collections: List[TestSourceTestOutputColllection]
+ output_collections: list[TestSourceTestOutputColllection]
stdout: NotRequired[AssertionList]
stderr: NotRequired[AssertionList]
- expect_exit_code: NotRequired[Optional[Union[str, int]]]
+ expect_exit_code: NotRequired[str | int | None]
expect_failure: NotRequired[bool]
expect_test_failure: NotRequired[bool]
- maxseconds: NotRequired[Optional[int]]
- num_outputs: NotRequired[Optional[Union[str, int]]]
+ maxseconds: NotRequired[int | None]
+ num_outputs: NotRequired[str | int | None]
command_line: NotRequired[AssertionList]
command_version: NotRequired[AssertionList]
required_files: NotRequired[RequiredFilesT]
required_data_tables: NotRequired[RequiredDataTablesT]
required_loc_files: NotRequired[RequiredLocFileT]
- credentials: NotRequired[Optional[List[DirectCredential]]]
+ credentials: NotRequired[list[DirectCredential] | None]
error: Literal[False]
tool_id: str
tool_version: str
@@ -162,19 +159,19 @@ class InvalidToolTestDict(TypedDict):
test_index: int
inputs: Any
exception: str
- request_unavailable_reason: NotRequired[Optional[str]]
- maxseconds: Optional[int]
+ request_unavailable_reason: NotRequired[str | None]
+ maxseconds: int | None
value_state_representation: NotRequired[ValueStateRepresentationT]
-ToolTestDict = Union[ValidToolTestDict, InvalidToolTestDict]
-ToolTestDictsT = List[ToolTestDict]
+ToolTestDict = ValidToolTestDict | InvalidToolTestDict
+ToolTestDictsT = list[ToolTestDict]
class PathOrLocation(NamedTuple):
name: str
- path: Optional[str]
- location: Optional[str]
+ path: str | None
+ location: str | None
def stage_data_in_history(
@@ -185,7 +182,7 @@ def stage_data_in_history(
force_path_paste=False,
maxseconds=DEFAULT_TOOL_TEST_WAIT,
tool_version=None,
- test_data_resolver: Optional[TestDataResolver] = None,
+ test_data_resolver: TestDataResolver | None = None,
):
assert tool_id, "Tool id not set"
@@ -210,35 +207,34 @@ def stage_data_in_history(
class RunToolResponse(NamedTuple):
- inputs: Dict[str, Any]
+ inputs: dict[str, Any]
outputs: OutputsDict
- output_collections: Dict[str, Any]
- jobs: List[Dict[str, Any]]
+ output_collections: dict[str, Any]
+ jobs: list[dict[str, Any]]
class ToolSubmissionResponse(NamedTuple):
- inputs: Dict[str, Any]
- tool_request_id: Optional[str] # None for legacy submissions
- submit_response_object: Dict[str, Any] # raw validated response
+ inputs: dict[str, Any]
+ tool_request_id: str | None # None for legacy submissions
+ submit_response_object: dict[str, Any] # raw validated response
is_legacy: bool
- cleanup: Optional[Callable[[], None]] = None
+ cleanup: Callable[[], None] | None = None
class InteractorStagingInterface(StagingInterface):
-
- def __init__(self, galaxy_interactor: "GalaxyInteractorApi", maxseconds: Optional[int], upload_async: bool) -> None:
+ def __init__(self, galaxy_interactor: "GalaxyInteractorApi", maxseconds: int | None, upload_async: bool) -> None:
super().__init__()
self.galaxy_interactor = galaxy_interactor
self.maxseconds = maxseconds or DEFAULT_TOOL_TEST_WAIT
self.upload_async = upload_async
- self.job_responses: List[Dict[str, Any]] = []
+ self.job_responses: list[dict[str, Any]] = []
- def _post(self, api_path: str, payload: Dict[str, Any]) -> Dict[str, Any]:
+ def _post(self, api_path: str, payload: dict[str, Any]) -> dict[str, Any]:
response = self.galaxy_interactor._post(api_path, payload, json=True)
assert response.status_code == 200, f"Staging failed: {response.text}"
return response.json()
- def _handle_job(self, job_response: Dict[str, Any]):
+ def _handle_job(self, job_response: dict[str, Any]):
if not self.upload_async:
return self.galaxy_interactor.wait_for_job(
job_response["id"], job_response["history_id"], maxseconds=self.maxseconds
@@ -269,9 +265,9 @@ def raise_for_status(response: Response) -> None:
class GalaxyInteractorApi:
# api_key and cookies can also be manually set by UsesApiTestCaseMixin._different_user()
- api_key: Optional[str]
- cookies: Optional[RequestsCookieJar]
- keep_outputs_dir: Optional[str]
+ api_key: str | None
+ cookies: RequestsCookieJar | None
+ keep_outputs_dir: str | None
def __init__(self, **kwds):
self.api_url = f"{kwds['galaxy_url'].rstrip('/')}/api"
@@ -302,9 +298,7 @@ class GalaxyInteractorApi:
def supports_test_data_download(self):
return self.target_galaxy_version >= Version("19.01")
- def _get_user_key(
- self, user_key: Optional[str], admin_key: Optional[str], test_user: Optional[str] = None
- ) -> Optional[str]:
+ def _get_user_key(self, user_key: str | None, admin_key: str | None, test_user: str | None = None) -> str | None:
if not test_user:
test_user = "test@bx.psu.edu"
if user_key:
@@ -319,7 +313,7 @@ class GalaxyInteractorApi:
assert response.status_code == 200, f"Non 200 response from tool tests available API. [{response.content}]"
return response.json()
- def get_tool_inputs(self, tool_id: str, tool_version: Optional[str] = None) -> ToolParameterBundle:
+ def get_tool_inputs(self, tool_id: str, tool_version: str | None = None) -> ToolParameterBundle:
url = f"tools/{tool_id}/inputs"
params = {"tool_version": tool_version} if tool_version else None
response = self._get(url, data=params)
@@ -328,7 +322,7 @@ class GalaxyInteractorApi:
tool_parameter_bundle = input_models_from_json(raw_inputs_array)
return tool_parameter_bundle
- def get_tool_tests(self, tool_id: str, tool_version: Optional[str] = None) -> List[ToolTestDescriptionDict]:
+ def get_tool_tests(self, tool_id: str, tool_version: str | None = None) -> list[ToolTestDescriptionDict]:
url = f"tools/{tool_id}/test_data"
params = {"tool_version": tool_version} if tool_version else None
response = self._get(url, data=params)
@@ -449,9 +443,8 @@ class GalaxyInteractorApi:
`dbkey` and `tags` all map to the API description directly. Other metadata attributes
are assumed to be datatype-specific and mapped with a prefix of `metadata_`.
"""
- metadata = get_metadata_to_test(attributes)
- if metadata:
+ if metadata := get_metadata_to_test(attributes):
def wait_for_content():
response = self._get(f"histories/{history_id}/contents/{hid}")
@@ -464,7 +457,7 @@ class GalaxyInteractorApi:
dataset = wait_on(wait_for_content, desc="dataset metadata", timeout=10)
compare_expected_metadata_to_api_response(metadata, dataset)
- def wait_for_job(self, job_id: str, history_id: Optional[str] = None, maxseconds=DEFAULT_TOOL_TEST_WAIT) -> None:
+ def wait_for_job(self, job_id: str, history_id: str | None = None, maxseconds=DEFAULT_TOOL_TEST_WAIT) -> None:
self.wait_for(lambda: self.__job_ready(job_id, history_id), maxseconds=maxseconds)
def wait_on_tool_request(self, tool_request_id: str):
@@ -489,7 +482,7 @@ class GalaxyInteractorApi:
walltime_exceeded = int(kwd.get("maxseconds", DEFAULT_TOOL_TEST_WAIT))
return wait_on(func, what, walltime_exceeded)
- def get_job_stdio(self, job_id: str) -> Dict[str, Any]:
+ def get_job_stdio(self, job_id: str) -> dict[str, Any]:
return self.__get_job_stdio(job_id).json()
def __get_job(self, job_id: str) -> Response:
@@ -498,7 +491,7 @@ class GalaxyInteractorApi:
def __get_job_stdio(self, job_id: str) -> Response:
return self._get(f"jobs/{job_id}?full=true")
- def get_history(self, history_name: str = "test_history") -> Optional[Dict[str, Any]]:
+ def get_history(self, history_name: str = "test_history") -> dict[str, Any] | None:
# Return the most recent non-deleted history matching the provided name
filters = urllib.parse.urlencode({"q": "name", "qv": history_name, "order": "update_time", "show_own": "true"})
response = self._get(f"histories?{filters}")
@@ -511,8 +504,8 @@ class GalaxyInteractorApi:
def test_history(
self,
require_new: bool = True,
- cleanup_callback: Optional[Callable[[str], None]] = None,
- name: Optional[str] = None,
+ cleanup_callback: Callable[[str], None] | None = None,
+ name: str | None = None,
) -> Generator[str, None, None]:
history_id = None
if not require_new:
@@ -529,7 +522,7 @@ class GalaxyInteractorApi:
if cleanup and cleanup_callback is not None:
cleanup_callback(history_id)
- def new_history(self, history_name: Optional[str] = None, publish_history: bool = False) -> str:
+ def new_history(self, history_name: str | None = None, publish_history: bool = False) -> str:
history_name = history_name or "test_history"
create_response = self._post("histories", {"name": history_name})
try:
@@ -554,8 +547,8 @@ class GalaxyInteractorApi:
raise Exception(result["err_msg"])
def test_data_download(self, tool_id, filename, mode="file", is_output=True, tool_version=None, path_only=False):
- result: Optional[Union[str, bytes]] = None
- local_path: Optional[str] = None
+ result: str | bytes | None = None
+ local_path: str | None = None
if self.supports_test_data_download:
version_fragment = f"&tool_version={tool_version}" if tool_version else ""
@@ -613,7 +606,7 @@ class GalaxyInteractorApi:
return result
- def _find_in_test_data_directories(self, filename: str) -> Optional[str]:
+ def _find_in_test_data_directories(self, filename: str) -> str | None:
local_path = None
for test_data_directory in self.test_data_directories:
local_path = os.path.join(test_data_directory, filename)
@@ -630,9 +623,7 @@ class GalaxyInteractorApi:
output_id = output_data
return output_id
- def remote_to_input(
- self, test_data, tool_id: str, force_path_paste: bool = False, tool_version: Optional[str] = None
- ):
+ def remote_to_input(self, test_data, tool_id: str, force_path_paste: bool = False, tool_version: str | None = None):
fname = test_data["fname"]
tags = test_data.get("tags")
tool_input = {
@@ -652,8 +643,7 @@ class GalaxyInteractorApi:
raise Exception(f"Invalid metadata description found for input [{fname}] - [{metadata}]")
tool_input["metadata"] = metadata
- composite_data = test_data["composite_data"]
- if composite_data:
+ if composite_data := test_data["composite_data"]:
tool_input["composite_data"] = [
self._get_path_or_location(
fname=fname_,
@@ -683,9 +673,9 @@ class GalaxyInteractorApi:
def _get_path_or_location(
self,
fname: str,
- test_data: Dict[str, Any],
+ test_data: dict[str, Any],
tool_id: str,
- tool_version: Optional[str] = None,
+ tool_version: str | None = None,
force_path_paste: bool = False,
mode: Literal["file", "directory"] = "file",
) -> PathOrLocation:
@@ -712,13 +702,13 @@ class GalaxyInteractorApi:
path = os.path.join(path, fname)
return PathOrLocation(name=fname, location=None, path=path)
- def _ensure_valid_location_in(self, test_data: dict) -> Optional[str]:
- location: Optional[str] = test_data.get("location")
+ def _ensure_valid_location_in(self, test_data: dict) -> str | None:
+ location: str | None = test_data.get("location")
if location and not util.is_url(location):
raise ValueError(f"Invalid `location` URL: `{location}`")
return location
- def _credential_api_call(self, method: str, path: str, data: Optional[Dict[str, Any]] = None) -> Any:
+ def _credential_api_call(self, method: str, path: str, data: dict[str, Any] | None = None) -> Any:
"""Low-level helper: call a credential API endpoint, raise on error, return JSON."""
if method == "post":
response = self._post(path, data=data or {}, json=True)
@@ -733,7 +723,7 @@ class GalaxyInteractorApi:
def _create_test_credentials(
self, testdef: "ToolTestDescription"
- ) -> Tuple[List[Dict[str, Any]], Optional[List[Dict[str, Any]]]]:
+ ) -> tuple[list[dict[str, Any]], list[dict[str, Any]] | None]:
"""Create vault credentials for a test and return (created_credentials, credentials_context)."""
if not testdef.credentials:
return [], None
@@ -796,7 +786,7 @@ class GalaxyInteractorApi:
self,
testdef: "ToolTestDescription",
history_id: str,
- resource_parameters: Optional[Dict[str, Any]] = None,
+ resource_parameters: dict[str, Any] | None = None,
use_legacy_api: UseLegacyApiT = DEFAULT_USE_LEGACY_API,
) -> "ToolSubmissionResponse":
# We need to handle the case where we've uploaded a valid compressed file since the upload
@@ -846,7 +836,7 @@ class GalaxyInteractorApi:
assert request_schema is not None, "Request schema not set"
parameters = request_schema["parameters"]
- def adapt_datasets(test_input: JsonTestDatasetDefDict) -> Union[DataRequestHda, DataRequestUri]:
+ def adapt_datasets(test_input: JsonTestDatasetDefDict) -> DataRequestHda | DataRequestUri:
location = test_input.get("location")
if location:
ext = test_input.get("filetype") or "auto"
@@ -873,7 +863,7 @@ class GalaxyInteractorApi:
submit_response = None
- extra_data: Dict[str, Any] = {}
+ extra_data: dict[str, Any] = {}
created_credentials, credentials_context = self._create_test_credentials(testdef)
if credentials_context is not None:
extra_data["credentials_context"] = dumps(credentials_context)
@@ -896,7 +886,7 @@ class GalaxyInteractorApi:
submit_response_object = ensure_tool_run_response_okay(submit_response, "execute tool", inputs_tree)
tool_request_id = None if submit_with_legacy_api else submit_response_object.get("tool_request_id")
- cleanup: Optional[Callable[[], None]] = None
+ cleanup: Callable[[], None] | None = None
if created_credentials:
def _cleanup_credentials():
@@ -939,7 +929,7 @@ class GalaxyInteractorApi:
job_id = job_refs[0]["id"]
jobs = [self.__get_job(job_id).json()]
outputs = OutputsDict()
- output_collections: Dict[str, Any] = {}
+ output_collections: dict[str, Any] = {}
for job_output in self.job_outputs(job_id):
if "dataset" in job_output:
outputs[job_output["name"]] = job_output["dataset"]
@@ -998,7 +988,7 @@ class GalaxyInteractorApi:
element_identifiers.append(element)
return element_identifiers
- def __dictify_output_collections(self, submit_response) -> Dict[str, Any]:
+ def __dictify_output_collections(self, submit_response) -> dict[str, Any]:
output_collections_dict = {}
for output_collection in submit_response["output_collections"]:
output_collections_dict[output_collection["output_name"]] = output_collection
@@ -1020,7 +1010,7 @@ class GalaxyInteractorApi:
def delete_history(self, history: str) -> None:
self._delete(f"histories/{history}")
- def __job_ready(self, job_id: str, history_id: Optional[str] = None):
+ def __job_ready(self, job_id: str, history_id: str | None = None):
if job_id is None:
raise ValueError("__job_ready passed empty job_id")
try:
@@ -1044,7 +1034,7 @@ class GalaxyInteractorApi:
dataset = history_content
print(ERROR_MESSAGE_DATASET_SEP)
- dataset_id: Optional[str] = dataset.get("id")
+ dataset_id: str | None = dataset.get("id")
if dataset_id is None:
print("| *TEST FRAMEWORK ERROR - NO DATASET ID*")
continue
@@ -1101,25 +1091,25 @@ class GalaxyInteractorApi:
contents = "\n".join(f"{prefix}{line.strip()}" for line in io.StringIO(blob).readlines() if line.rstrip("\n\r"))
return contents or f"{prefix}*{empty_message}*"
- def _dataset_provenance(self, history_id: str, id: str) -> Dict[str, Any]:
+ def _dataset_provenance(self, history_id: str, id: str) -> dict[str, Any]:
provenance = self._get(f"histories/{history_id}/contents/{id}/provenance").json()
return provenance
- def _dataset_info(self, history_id: str, id: str) -> Dict[str, Any]:
+ def _dataset_info(self, history_id: str, id: str) -> dict[str, Any]:
dataset_json = self._get(f"histories/{history_id}/contents/{id}").json()
return dataset_json
- def jobs_for_tool_request(self, tool_request_id: str) -> List[Dict[str, Any]]:
+ def jobs_for_tool_request(self, tool_request_id: str) -> list[dict[str, Any]]:
job_list_response = self._get(f"tool_requests/{tool_request_id}")
job_list_response.raise_for_status()
return job_list_response.json()["jobs"]
- def job_outputs(self, job_id: str) -> List[Dict[str, Any]]:
+ def job_outputs(self, job_id: str) -> list[dict[str, Any]]:
outputs = self._get(f"jobs/{job_id}/outputs")
outputs.raise_for_status()
return outputs.json()
- def __contents(self, history_id: str) -> List[Dict[str, Any]]:
+ def __contents(self, history_id: str) -> list[dict[str, Any]]:
history_contents_response = self._get(f"histories/{history_id}/contents")
history_contents_response.raise_for_status()
return history_contents_response.json()
@@ -1139,10 +1129,10 @@ class GalaxyInteractorApi:
self,
history_id: str,
tool_id: str,
- tool_input: Optional[dict],
- extra_data: Optional[dict] = None,
- files: Optional[dict] = None,
- tool_version: Optional[str] = None,
+ tool_input: dict | None,
+ extra_data: dict | None = None,
+ files: dict | None = None,
+ tool_version: str | None = None,
use_legacy_api: bool = True,
):
extra_data = extra_data or {}
@@ -1190,7 +1180,7 @@ class GalaxyInteractorApi:
test_user = self._post("users", data, key=admin_key, json=True).json()
return test_user
- def __test_data_downloader(self, tool_id, tool_version=None, attributes: Optional[dict] = None):
+ def __test_data_downloader(self, tool_id, tool_version=None, attributes: dict | None = None):
location = None
checksum = attributes.get("checksum") if attributes else None
@@ -1222,7 +1212,7 @@ class GalaxyInteractorApi:
return test_data_download_from_location
return test_data_download_from_galaxy
- def _verify_checksum(self, file_path: str, checksum: Optional[str] = None):
+ def _verify_checksum(self, file_path: str, checksum: str | None = None):
if checksum is None:
return
hash_function, expected_hash_value = parse_checksum_hash(checksum)
@@ -1254,8 +1244,8 @@ class GalaxyInteractorApi:
return fetcher
def api_key_header(
- self, key: Optional[str], admin: bool, anon: bool, headers: Optional[Dict[str, Optional[str]]]
- ) -> Dict[str, Optional[str]]:
+ self, key: str | None, admin: bool, anon: bool, headers: dict[str, str | None] | None
+ ) -> dict[str, str | None]:
header = headers or {}
if not anon:
if not key:
@@ -1266,10 +1256,10 @@ class GalaxyInteractorApi:
def _post(
self,
path: str,
- data: Optional[Dict[str, Any]] = None,
- files: Optional[Dict[str, Any]] = None,
- key: Optional[str] = None,
- headers: Optional[Dict[str, Optional[str]]] = None,
+ data: dict[str, Any] | None = None,
+ files: dict[str, Any] | None = None,
+ key: str | None = None,
+ headers: dict[str, str | None] | None = None,
admin: bool = False,
anon: bool = False,
json: bool = False,
@@ -1283,9 +1273,9 @@ class GalaxyInteractorApi:
def _options(
self,
path: str,
- data: Optional[Dict[str, Any]] = None,
- key: Optional[str] = None,
- headers: Optional[Dict[str, Optional[str]]] = None,
+ data: dict[str, Any] | None = None,
+ key: str | None = None,
+ headers: dict[str, str | None] | None = None,
admin: bool = False,
anon: bool = False,
json: bool = False,
@@ -1320,7 +1310,7 @@ class GalaxyInteractorApi:
def _get(self, path, data=None, key=None, headers=None, admin=False, anon=False, allow_redirects=True):
headers = self.api_key_header(key=key, admin=admin, anon=anon, headers=headers)
url = self.get_api_url(path)
- kwargs: Dict[str, Any] = {}
+ kwargs: dict[str, Any] = {}
if self.cookies:
kwargs["cookies"] = self.cookies
# no data for GET
@@ -1336,7 +1326,7 @@ class GalaxyInteractorApi:
def _head(self, path, data=None, key=None, headers=None, admin=False, anon=False):
headers = self.api_key_header(key=key, admin=admin, anon=anon, headers=headers)
url = self.get_api_url(path)
- kwargs: Dict[str, Any] = {}
+ kwargs: dict[str, Any] = {}
if self.cookies:
kwargs["cookies"] = self.cookies
# no data for HEAD
@@ -1351,12 +1341,12 @@ class GalaxyInteractorApi:
def _prepare_request_params(
self,
- data: Optional[Dict[str, Any]] = None,
- files: Optional[Dict[str, Any]] = None,
+ data: dict[str, Any] | None = None,
+ files: dict[str, Any] | None = None,
as_json: bool = False,
- params: Optional[Dict[str, Any]] = None,
- headers: Optional[Dict[str, Optional[str]]] = None,
- ) -> Dict[str, Any]:
+ params: dict[str, Any] | None = None,
+ headers: dict[str, str | None] | None = None,
+ ) -> dict[str, Any]:
"""Handle some Galaxy conventions and work around requests issues.
This is admittedly kind of hacky, so the interface may change frequently - be
@@ -1374,13 +1364,13 @@ class GalaxyInteractorApi:
def prepare_request_params(
- data: Optional[Dict[str, Any]] = None,
- files: Optional[Dict[str, Any]] = None,
+ data: dict[str, Any] | None = None,
+ files: dict[str, Any] | None = None,
as_json: bool = False,
- params: Optional[Dict[str, Any]] = None,
- headers: Optional[Dict[str, Optional[str]]] = None,
- cookies: Optional[RequestsCookieJar] = None,
-) -> Dict[str, Any]:
+ params: dict[str, Any] | None = None,
+ headers: dict[str, str | None] | None = None,
+ cookies: RequestsCookieJar | None = None,
+) -> dict[str, Any]:
params = params or {}
data = data or {}
@@ -1402,7 +1392,7 @@ def prepare_request_params(
new_items[key] = dumps(val)
data.update(new_items)
- kwd: Dict[str, Any] = {
+ kwd: dict[str, Any] = {
"files": files,
}
if headers:
@@ -1465,12 +1455,12 @@ class RunToolException(Exception):
# Galaxy specific methods - rest of this can be used with arbitrary files and such.
def verify_hid(
- filename: Optional[str],
+ filename: str | None,
hda_id: str,
- attributes: Dict[str, Any],
+ attributes: dict[str, Any],
test_data_downloader,
dataset_fetcher=None,
- keep_outputs_dir: Optional[str] = None,
+ keep_outputs_dir: str | None = None,
):
assert dataset_fetcher is not None
@@ -1499,8 +1489,7 @@ def verify_hid(
def verify_collection(output_collection_def, data_collection, verify_dataset):
name = output_collection_def.name
- expected_collection_type = output_collection_def.collection_type
- if expected_collection_type:
+ if expected_collection_type := output_collection_def.collection_type:
collection_type = data_collection["collection_type"]
if expected_collection_type != collection_type:
message = f"Output collection '{name}': expected to be of type [{expected_collection_type}], was of type [{collection_type}]."
@@ -1585,7 +1574,7 @@ def _verify_composite_datatype_file_content(
attributes=None,
dataset_fetcher=None,
test_data_downloader=None,
- keep_outputs_dir: Optional[str] = None,
+ keep_outputs_dir: str | None = None,
mode="file",
):
assert dataset_fetcher is not None
@@ -1609,7 +1598,7 @@ def _verify_composite_datatype_file_content(
def _verify_extra_files_content(
- extra_files: List[Dict[str, Any]], hda_id: str, dataset_fetcher, test_data_downloader, keep_outputs_dir
+ extra_files: list[dict[str, Any]], hda_id: str, dataset_fetcher, test_data_downloader, keep_outputs_dir
):
files_list = []
cleanup_directories = []
@@ -1651,7 +1640,7 @@ def _verify_extra_files_content(
class TestConfig(Protocol):
- def get_test_config(self, job_data: Dict[str, Any]) -> Optional[Dict[str, Any]]: ...
+ def get_test_config(self, job_data: dict[str, Any]) -> dict[str, Any] | None: ...
class NullClientTestConfig(TestConfig):
@@ -1699,22 +1688,22 @@ class DictClientTestConfig(TestConfig):
def verify_tool(
tool_id: str,
galaxy_interactor: "GalaxyInteractorApi",
- resource_parameters: Optional[Dict[str, Any]] = None,
- register_job_data: Optional[JobDataCallbackT] = None,
+ resource_parameters: dict[str, Any] | None = None,
+ register_job_data: JobDataCallbackT | None = None,
test_index: int = 0,
- tool_version: Optional[str] = None,
+ tool_version: str | None = None,
use_legacy_api: UseLegacyApiT = DEFAULT_USE_LEGACY_API,
quiet: bool = False,
- test_history: Optional[str] = None,
+ test_history: str | None = None,
no_history_cleanup: bool = False,
publish_history: bool = False,
force_path_paste: bool = False,
maxseconds: int = DEFAULT_TOOL_TEST_WAIT,
- client_test_config: Optional[TestConfig] = None,
+ client_test_config: TestConfig | None = None,
skip_with_reference_data: bool = False,
skip_on_dynamic_param_errors: bool = False,
- _tool_test_dicts: Optional[List[ToolTestDescriptionDict]] = None, # extension point only for tests
- test_data_resolver: Optional[TestDataResolver] = None,
+ _tool_test_dicts: list[ToolTestDescriptionDict] | None = None, # extension point only for tests
+ test_data_resolver: TestDataResolver | None = None,
):
if resource_parameters is None:
resource_parameters = {}
@@ -1730,9 +1719,8 @@ def verify_tool(
"tool_version": tool_version,
"test_index": test_index,
}
- client_config = client_test_config.get_test_config(job_data)
skip_message = None
- if client_config is not None:
+ if (client_config := client_test_config.get_test_config(job_data)) is not None:
job_data.update(client_config)
skip_message = job_data.get("skip")
@@ -1767,10 +1755,10 @@ def verify_tool(
tool_inputs = None
job_stdio = None
job_output_exceptions = None
- tool_execution_exception: Optional[Exception] = None
+ tool_execution_exception: Exception | None = None
input_staging_exc_info = None
expected_failure_occurred = False
- credential_cleanup: Optional[Callable[[], None]] = None
+ credential_cleanup: Callable[[], None] | None = None
begin_time = time.time()
try:
try:
@@ -1869,7 +1857,7 @@ def _handle_def_errors(testdef):
def _verify_outputs(testdef, history, jobs, data_list, data_collection_list, galaxy_interactor, quiet=False):
assert len(jobs) == 1, "Test framework logic error, somehow tool test resulted in more than one job."
job = jobs[0]
- found_exceptions: List[Exception] = []
+ found_exceptions: list[Exception] = []
def register_exception(e: Exception):
if not found_exceptions and not quiet:
@@ -1908,8 +1896,7 @@ def _verify_outputs(testdef, history, jobs, data_list, data_collection_list, gal
error = AssertionError("Expected job to fail but Galaxy indicated the job successfully completed.")
register_exception(error)
- expect_exit_code = testdef.expect_exit_code
- if expect_exit_code is not None:
+ if (expect_exit_code := testdef.expect_exit_code) is not None:
exit_code = job_stdio["exit_code"]
if str(expect_exit_code) != str(exit_code):
error = AssertionError(f"Expected job to complete with exit code {expect_exit_code}, found {exit_code}")
@@ -2009,20 +1996,20 @@ class JobOutputsError(AssertionError):
self.output_exceptions = output_exceptions
-DEFAULT_NUM_OUTPUTS: Optional[int] = None
-DEFAULT_OUTPUT_COLLECTIONS: List[TestSourceTestOutputColllection] = []
+DEFAULT_NUM_OUTPUTS: int | None = None
+DEFAULT_OUTPUT_COLLECTIONS: list[TestSourceTestOutputColllection] = []
DEFAULT_REQUIRED_FILES: RequiredFilesT = []
DEFAULT_REQUIRED_DATA_TABLES: RequiredDataTablesT = []
DEFAULT_REQUIRED_LOC_FILES: RequiredLocFileT = []
-DEFAULT_COMMAND_LINE: Optional[AssertionList] = []
-DEFAULT_COMMAND_VERSION: Optional[AssertionList] = []
-DEFAULT_STDOUT: Optional[AssertionList] = []
-DEFAULT_STDERR: Optional[AssertionList] = []
+DEFAULT_COMMAND_LINE: AssertionList | None = []
+DEFAULT_COMMAND_VERSION: AssertionList | None = []
+DEFAULT_STDOUT: AssertionList | None = []
+DEFAULT_STDERR: AssertionList | None = []
DEFAULT_OUTPUTS: ToolSourceTestOutputs = []
-DEFAULT_EXPECT_EXIT_CODE: Optional[int] = None
+DEFAULT_EXPECT_EXIT_CODE: int | None = None
DEFAULT_EXPECT_FAILURE: bool = False
DEFAULT_EXPECT_TEST_FAILURE: bool = False
-DEFAULT_EXCEPTION: Optional[str] = None
+DEFAULT_EXCEPTION: str | None = None
def adapt_tool_source_dict(processed_dict: ToolTestDict) -> ToolTestDescriptionDict:
@@ -2035,26 +2022,26 @@ def adapt_tool_source_dict(processed_dict: ToolTestDict) -> ToolTestDescriptionD
name = _get_test_name(processed_dict, test_index)
error_in_test_definition = processed_dict["error"]
- exception: Optional[str] = DEFAULT_EXCEPTION
- output_collections: List[TestSourceTestOutputColllection] = []
- num_outputs: Optional[int] = DEFAULT_NUM_OUTPUTS
+ exception: str | None = DEFAULT_EXCEPTION
+ output_collections: list[TestSourceTestOutputColllection] = []
+ num_outputs: int | None = DEFAULT_NUM_OUTPUTS
required_files: RequiredFilesT = DEFAULT_REQUIRED_FILES
required_data_tables: RequiredDataTablesT = DEFAULT_REQUIRED_DATA_TABLES
required_loc_files: RequiredLocFileT = DEFAULT_REQUIRED_LOC_FILES
- command_line: Optional[AssertionList] = DEFAULT_COMMAND_LINE
- command_version: Optional[AssertionList] = DEFAULT_COMMAND_VERSION
- stdout: Optional[AssertionList] = DEFAULT_STDERR
- stderr: Optional[AssertionList] = DEFAULT_STDERR
+ command_line: AssertionList | None = DEFAULT_COMMAND_LINE
+ command_version: AssertionList | None = DEFAULT_COMMAND_VERSION
+ stdout: AssertionList | None = DEFAULT_STDERR
+ stderr: AssertionList | None = DEFAULT_STDERR
outputs: ToolSourceTestOutputs = DEFAULT_OUTPUTS
- expect_exit_code: Optional[int] = DEFAULT_EXPECT_EXIT_CODE
+ expect_exit_code: int | None = DEFAULT_EXPECT_EXIT_CODE
expect_failure: bool = DEFAULT_EXPECT_FAILURE
expect_test_failure: bool = DEFAULT_EXPECT_TEST_FAILURE
inputs: ExpandedToolInputsJsonified = {}
- maxseconds: Optional[int] = None
- request: Optional[Dict[str, Any]] = None
- request_schema: Optional[Dict[str, Any]] = None
- request_unavailable_reason: Optional[str] = None
- credentials: Optional[List[DirectCredential]] = None
+ maxseconds: int | None = None
+ request: dict[str, Any] | None = None
+ request_schema: dict[str, Any] | None = None
+ request_unavailable_reason: str | None = None
+ credentials: list[DirectCredential] | None = None
if not error_in_test_definition:
processed_test_dict = cast(ValidToolTestDict, processed_dict)
@@ -2071,9 +2058,7 @@ def adapt_tool_source_dict(processed_dict: ToolTestDict) -> ToolTestDescriptionD
stdout = processed_test_dict.get("stdout", DEFAULT_STDOUT)
stderr = processed_test_dict.get("stderr", DEFAULT_STDERR)
outputs = processed_test_dict.get("outputs", DEFAULT_OUTPUTS)
- raw_expect_exit_code: Optional[Union[str, int]] = processed_test_dict.get(
- "expect_exit_code", DEFAULT_EXPECT_EXIT_CODE
- )
+ raw_expect_exit_code: str | int | None = processed_test_dict.get("expect_exit_code", DEFAULT_EXPECT_EXIT_CODE)
if raw_expect_exit_code is not None:
expect_exit_code = int(raw_expect_exit_code)
@@ -2121,12 +2106,12 @@ def adapt_tool_source_dict(processed_dict: ToolTestDict) -> ToolTestDescriptionD
)
-def _get_test_index(test_dict: Union[ToolTestDict, ToolTestDescriptionDict]) -> int:
+def _get_test_index(test_dict: ToolTestDict | ToolTestDescriptionDict) -> int:
assert "test_index" in test_dict, "Invalid processed test description, must have a 'test_index' for naming, etc.."
return test_dict["test_index"]
-def _get_test_name(test_dict: Union[ToolTestDict, ToolTestDescriptionDict], test_index: int) -> str:
+def _get_test_name(test_dict: ToolTestDict | ToolTestDescriptionDict, test_index: int) -> str:
name = cast(str, test_dict.get("name", f"Test-{test_index + 1}"))
return name
@@ -2162,29 +2147,29 @@ class ToolTestDescription:
name: str
tool_id: str
- tool_version: Optional[str]
+ tool_version: str | None
test_index: int
- num_outputs: Optional[int]
- stdout: Optional[AssertionList]
- stderr: Optional[AssertionList]
- command_line: Optional[AssertionList]
- command_version: Optional[AssertionList]
+ num_outputs: int | None
+ stdout: AssertionList | None
+ stderr: AssertionList | None
+ command_line: AssertionList | None
+ command_version: AssertionList | None
required_files: RequiredFilesT
required_data_tables: RequiredDataTablesT
required_loc_files: RequiredLocFileT
- expect_exit_code: Optional[int]
+ expect_exit_code: int | None
expect_failure: bool
expect_test_failure: bool
- exception: Optional[str]
- request_unavailable_reason: Optional[str]
+ exception: str | None
+ request_unavailable_reason: str | None
inputs: ExpandedToolInputs
- request: Optional[Dict[str, Any]]
- request_schema: Optional[Dict[str, Any]]
+ request: dict[str, Any] | None
+ request_schema: dict[str, Any] | None
outputs: ToolSourceTestOutputs
- output_collections: List[TestCollectionOutputDef]
- maxseconds: Optional[int]
+ output_collections: list[TestCollectionOutputDef]
+ maxseconds: int | None
value_state_representation: ValueStateRepresentationT
- credentials: Optional[List[DirectCredential]]
+ credentials: list[DirectCredential] | None
@staticmethod
def from_tool_source_dict(processed_test_dict: ToolTestDict) -> "ToolTestDescription":
@@ -2323,7 +2308,6 @@ def get_metadata_to_test(test_properties: dict) -> dict:
elif key == "info":
metadata["misc_info"] = metadata["info"]
del metadata["info"]
- expected_file_type = test_properties.get("ftype", None)
- if expected_file_type:
+ if expected_file_type := test_properties.get("ftype", None):
metadata["file_ext"] = expected_file_type
return metadata
diff --git a/lib/galaxy/tool_util/verify/parse.py b/lib/galaxy/tool_util/verify/parse.py
index 4f958f26ca4..43f2a7637c1 100644
--- a/lib/galaxy/tool_util/verify/parse.py
+++ b/lib/galaxy/tool_util/verify/parse.py
@@ -1,19 +1,15 @@
import logging
import os
import traceback
+from collections.abc import Iterable
from dataclasses import dataclass
from typing import (
Any,
- Dict,
- Iterable,
- List,
- Optional,
- Tuple,
+ Literal,
Union,
)
from packaging.version import Version
-from typing_extensions import Literal
from galaxy.tool_util.parameters import (
input_models_for_tool_source,
@@ -61,24 +57,24 @@ AnyParamContext = Union["ParamContext", "RootParamContext"]
def parse_tool_test_descriptions(
- tool_source: ToolSource, tool_guid: Optional[str] = None, parameters: Optional[List[ToolParameterT]] = None
+ tool_source: ToolSource, tool_guid: str | None = None, parameters: list[ToolParameterT] | None = None
) -> Iterable[ToolTestDescription]:
"""
Build ToolTestDescription objects for each test description.
"""
profile = tool_source.parse_profile()
validate_on_load = Version(profile) >= Version("24.2")
- validation_skipped_reason: Optional[str] = None
+ validation_skipped_reason: str | None = None
if not validate_on_load:
validation_skipped_reason = f"tool profile {profile} < 24.2, validation skipped"
raw_tests_dict: ToolSourceTests = tool_source.parse_tests_to_dict()
- tests: List[ToolTestDescription] = []
+ tests: list[ToolTestDescription] = []
for i, raw_test_dict in enumerate(raw_tests_dict.get("tests", [])):
- validation_exception: Optional[Exception] = None
- request_and_schema: Optional[TestRequestAndSchema] = None
- tool_parameter_bundle: Optional[ToolParameterBundleModel] = None
+ validation_exception: Exception | None = None
+ request_and_schema: TestRequestAndSchema | None = None
+ tool_parameter_bundle: ToolParameterBundleModel | None = None
try:
if parameters is None:
tool_parameter_bundle = input_models_for_tool_source(tool_source)
@@ -128,9 +124,9 @@ def _description_from_tool_source(
tool_source: ToolSource,
raw_test_dict: ToolSourceTest,
test_index: int,
- tool_guid: Optional[str],
- request_and_schema: Optional[TestRequestAndSchema],
- request_unavailable_reason: Optional[str],
+ tool_guid: str | None,
+ request_and_schema: TestRequestAndSchema | None,
+ request_unavailable_reason: str | None,
) -> ToolTestDescription:
required_files: RequiredFilesT = []
required_data_tables: RequiredDataTablesT = []
@@ -143,15 +139,15 @@ def _description_from_tool_source(
if maxseconds is not None:
maxseconds = int(maxseconds)
- request: Optional[Dict[str, Any]] = None
- request_schema: Optional[Dict[str, Any]] = None
+ request: dict[str, Any] | None = None
+ request_schema: dict[str, Any] | None = None
if request_and_schema:
request = request_and_schema.request.input_state
request_schema = request_and_schema.request_schema.model_dump()
value_state_representation = raw_test_dict.get("value_state_representation", "test_case_xml")
tool_id, tool_version = _tool_id_and_version(tool_source, tool_guid)
- processed_test_dict: Union[ValidToolTestDict, InvalidToolTestDict]
+ processed_test_dict: ValidToolTestDict | InvalidToolTestDict
try:
processed_inputs = _process_raw_inputs(
tool_source,
@@ -208,7 +204,7 @@ def _description_from_tool_source(
return ToolTestDescription.from_tool_source_dict(processed_test_dict)
-def _tool_id_and_version(tool_source: ToolSource, tool_guid: Optional[str]) -> Tuple[str, str]:
+def _tool_id_and_version(tool_source: ToolSource, tool_guid: str | None) -> tuple[str, str]:
tool_id = tool_guid or tool_source.parse_id()
assert tool_id
tool_version = parse_tool_version_with_defaults(tool_id, tool_source)
@@ -217,13 +213,13 @@ def _tool_id_and_version(tool_source: ToolSource, tool_guid: Optional[str]) -> T
def _process_raw_inputs(
tool_source: ToolSource,
- input_sources: List[InputSource],
+ input_sources: list[InputSource],
raw_inputs: ToolSourceTestInputs,
value_state_representation: Literal["test_case_xml", "test_case_json"],
required_files: RequiredFilesT,
required_data_tables: RequiredDataTablesT,
required_loc_files: RequiredLocFileT,
- parent_context: Optional[AnyParamContext] = None,
+ parent_context: AnyParamContext | None = None,
) -> ExpandedToolInputs:
"""
Recursively expand flat list of inputs into "tree" form of flat list
@@ -369,7 +365,7 @@ def _process_raw_inputs(
return expanded_inputs
-def input_sources(tool_source: ToolSource) -> List[InputSource]:
+def input_sources(tool_source: ToolSource) -> list[InputSource]:
input_sources = []
pages_source = tool_source.parse_input_pages()
if pages_source.inputs_defined:
@@ -385,13 +381,13 @@ class ParamContext:
parent_context: AnyParamContext
name: str
# if in a repeat - what position in the repeat
- index: Optional[int]
+ index: int | None
# we've encouraged the use of repeat/conditional tags to capture fully qualified paths
# to parameters in tools. This brings the parameters closer to the API and prevents a
# variety of possible ambiguities. Disable this for newer tools.
allow_unqualified_access: bool
- def __init__(self, name: str, parent_context: AnyParamContext, index: Optional[int] = None):
+ def __init__(self, name: str, parent_context: AnyParamContext, index: int | None = None):
self.parent_context = parent_context
self.name = name
self.index = None if index is None else int(index)
@@ -399,8 +395,7 @@ class ParamContext:
def for_state(self) -> str:
name = self.name if self.index is None else f"{self.name}_{self.index}"
- parent_for_state = self.parent_context.for_state()
- if parent_for_state:
+ if parent_for_state := self.parent_context.for_state():
return f"{parent_for_state}|{name}"
else:
return name
@@ -483,8 +478,7 @@ def _process_simple_value(
found_value = True
if value_for_text is None and param_value == text:
value_for_text = opt_value
- dynamic_options = param.parse_dynamic_options()
- if dynamic_options:
+ if dynamic_options := param.parse_dynamic_options():
data_table_name = dynamic_options.get_data_table_name()
index_file_name = dynamic_options.get_index_file_name()
if data_table_name:
@@ -583,11 +577,11 @@ def _matching_case_for_value(
def _add_uploaded_dataset(
name: str,
- value: Optional[str],
+ value: str | None,
extra: ExtraFileInfoDictT,
input_parameter: InputSource,
required_files: RequiredFilesT,
-) -> Optional[str]:
+) -> str | None:
if value is None:
assert (
input_parameter.parse_optional() or "composite_data" in extra
@@ -651,8 +645,7 @@ def split_if_str(value):
# into the YAML structure consumed by the test framework {that: string, **atributes}
def tag_structure_to_that_structure(raw_assert):
as_json = {"that": raw_assert["tag"], **raw_assert.get("attributes", {})}
- children = raw_assert.get("children")
- if children:
+ if children := raw_assert.get("children"):
as_json["children"] = list(map(tag_structure_to_that_structure, children))
return as_json
diff --git a/lib/galaxy/tool_util/verify/script.py b/lib/galaxy/tool_util/verify/script.py
index fca086cf132..99bca03f8aa 100644
--- a/lib/galaxy/tool_util/verify/script.py
+++ b/lib/galaxy/tool_util/verify/script.py
@@ -8,17 +8,14 @@ import logging
import os
import sys
import tempfile
+from collections.abc import Callable
from concurrent.futures import (
thread,
ThreadPoolExecutor,
)
from typing import (
Any,
- Callable,
- Dict,
- List,
NamedTuple,
- Optional,
)
import yaml
@@ -40,7 +37,7 @@ LATEST_VERSION = None
class TestReference(NamedTuple):
tool_id: str
- tool_version: Optional[str]
+ tool_version: str | None
test_index: int
@@ -51,10 +48,10 @@ class TestException(NamedTuple):
class Results:
- test_exceptions: List[TestException]
+ test_exceptions: list[TestException]
def __init__(
- self, default_suitename: str, test_json: str, append: bool = False, galaxy_url: Optional[str] = None
+ self, default_suitename: str, test_json: str, append: bool = False, galaxy_url: str | None = None
) -> None:
self.test_json = test_json or "-"
self.galaxy_url = galaxy_url
@@ -72,29 +69,27 @@ class Results:
self.test_exceptions = []
self.suitename = suitename
- def register_result(self, result: Dict[str, Any]) -> None:
+ def register_result(self, result: dict[str, Any]) -> None:
self.test_results.append(result)
def register_exception(self, test_exception: TestException) -> None:
self.test_exceptions.append(test_exception)
def already_successful(self, test_reference: TestReference) -> bool:
- test_data = self._previous_test_data(test_reference)
- if test_data:
+ if test_data := self._previous_test_data(test_reference):
if "status" in test_data and test_data["status"] == "success":
return True
return False
def already_executed(self, test_reference: TestReference) -> bool:
- test_data = self._previous_test_data(test_reference)
- if test_data:
+ if test_data := self._previous_test_data(test_reference):
if "status" in test_data and test_data["status"] != "skipped":
return True
return False
- def _previous_test_data(self, test_reference: TestReference) -> Optional[Dict[str, Any]]:
+ def _previous_test_data(self, test_reference: TestReference) -> dict[str, Any] | None:
test_id = _test_id_for_reference(test_reference)
for test_result in self.test_results:
if test_result.get("id") != test_id:
@@ -157,29 +152,29 @@ class Results:
messages.append("Errored tool tests ({}): {}".format(len(errored_tests), [t["id"] for t in errored_tests]))
return "\n".join(messages)
- def _tests_with_status(self, status: str) -> List[Dict[str, Any]]:
+ def _tests_with_status(self, status: str) -> list[dict[str, Any]]:
return [t for t in self.test_results if t.get("data", {}).get("status") == status]
def test_tools(
galaxy_interactor: GalaxyInteractorApi,
- test_references: List[TestReference],
+ test_references: list[TestReference],
results: Results,
- log: Optional[logging.Logger] = None,
+ log: logging.Logger | None = None,
parallel_tests: int = 1,
history_per_test_case: bool = False,
- history_name: Optional[str] = None,
+ history_name: str | None = None,
no_history_reuse: bool = False,
no_history_cleanup: bool = False,
publish_history: bool = False,
retries: int = 0,
- verify_kwds: Optional[Dict[str, Any]] = None,
+ verify_kwds: dict[str, Any] | None = None,
) -> None:
"""Run through tool tests and write report."""
verify_kwds = (verify_kwds or {}).copy()
tool_test_start = dt.datetime.now()
history_created = False
- test_history: Optional[str] = None
+ test_history: str | None = None
if not history_per_test_case:
if not history_name:
history_name = f"History for {results.suitename}"
@@ -256,10 +251,10 @@ def _test_tool(
test_reference: "TestReference",
results: Results,
galaxy_interactor: GalaxyInteractorApi,
- log: Optional[logging.Logger],
+ log: logging.Logger | None,
retries: int,
publish_history: bool,
- verify_kwds: Dict[str, Any],
+ verify_kwds: dict[str, Any],
) -> None:
tool_id = test_reference.tool_id
tool_version = test_reference.tool_version
@@ -324,14 +319,14 @@ def _test_tool(
def build_case_references(
galaxy_interactor: GalaxyInteractorApi,
tool_id: str = ALL_TOOLS,
- tool_version: Optional[str] = LATEST_VERSION,
+ tool_version: str | None = LATEST_VERSION,
test_index: int = ALL_TESTS,
page_size: int = 0,
page_number: int = 0,
- test_filters: Optional[List[Callable[[TestReference], bool]]] = None,
- log: Optional[logging.Logger] = None,
-) -> List[TestReference]:
- test_references: List[TestReference] = []
+ test_filters: list[Callable[[TestReference], bool]] | None = None,
+ log: logging.Logger | None = None,
+) -> list[TestReference]:
+ test_references: list[TestReference] = []
if tool_id == ALL_TOOLS:
tests_summary = galaxy_interactor.get_tests_summary()
for tool_id, tool_versions_dict in tests_summary.items():
@@ -341,7 +336,7 @@ def build_case_references(
test_references.append(test_reference)
else:
assert tool_id
- tool_test_dicts: List[ToolTestDescriptionDict] = galaxy_interactor.get_tool_tests(
+ tool_test_dicts: list[ToolTestDescriptionDict] = galaxy_interactor.get_tool_tests(
tool_id, tool_version=tool_version
)
for i, tool_test_dict in enumerate(tool_test_dicts):
@@ -352,7 +347,7 @@ def build_case_references(
test_references.append(test_reference)
if test_filters is not None and len(test_filters) > 0:
- filtered_test_references: List[TestReference] = []
+ filtered_test_references: list[TestReference] = []
for test_reference in test_references:
skip_test = False
for test_filter in test_filters:
@@ -390,16 +385,15 @@ def main(argv=None) -> None:
def run_tests(
args: argparse.Namespace,
- test_filters: Optional[List[Callable[[TestReference], bool]]] = None,
- log: Optional[logging.Logger] = None,
+ test_filters: list[Callable[[TestReference], bool]] | None = None,
+ log: logging.Logger | None = None,
) -> None:
# Split out argument parsing so we can quickly build other scripts - such as a script
# to run all tool tests for a workflow by just passing in a custom test_filters.
test_filters = test_filters or []
log = log or setup_global_logger(__name__, verbose=args.verbose)
- client_test_config_path = args.client_test_config
- if client_test_config_path is not None:
+ if (client_test_config_path := args.client_test_config) is not None:
log.debug(f"Reading client config path {client_test_config_path}")
with open(client_test_config_path) as f:
client_test_config = yaml.full_load(f)
@@ -469,13 +463,12 @@ def run_tests(
publish_history=get_option("publish_history"),
verify_kwds=verify_kwds,
)
- exceptions = results.test_exceptions
- if exceptions:
+ if exceptions := results.test_exceptions:
exception = exceptions[0]
raise exception.exception
-def setup_global_logger(name: str, log_file: Optional[str] = None, verbose: bool = False) -> logging.Logger:
+def setup_global_logger(name: str, log_file: str | None = None, verbose: bool = False) -> logging.Logger:
formatter = logging.Formatter("%(asctime)s %(levelname)-5s - %(message)s")
console = logging.StreamHandler()
console.setFormatter(formatter)
diff --git a/lib/galaxy/tool_util/version.py b/lib/galaxy/tool_util/version.py
index 4f17224417a..3219f1343b1 100644
--- a/lib/galaxy/tool_util/version.py
+++ b/lib/galaxy/tool_util/version.py
@@ -24,10 +24,8 @@
# was removed: https://github.com/pypa/packaging/blob/21.3/packaging/version.py
import re
+from collections.abc import Iterator
from typing import (
- Iterator,
- List,
- Tuple,
Union,
)
@@ -39,7 +37,7 @@ from packaging.version import (
__all__ = ["parse_version", "LegacyVersion"]
-LegacyCmpKey = Tuple[int, Tuple[str, ...]]
+LegacyCmpKey = tuple[int, tuple[str, ...]]
def parse_version(version: str) -> Union["LegacyVersion", Version]:
@@ -150,7 +148,7 @@ def _legacy_cmpkey(version: str) -> LegacyCmpKey:
# This scheme is taken from pkg_resources.parse_version setuptools prior to
# it's adoption of the packaging library.
- parts: List[str] = []
+ parts: list[str] = []
for part in _parse_version_parts(version.lower()):
if part.startswith("*"):
# remove "-" before a prerelease tag
diff --git a/lib/galaxy/tool_util/version_updates.py b/lib/galaxy/tool_util/version_updates.py
index 073fb9d45a7..f2f14d77285 100644
--- a/lib/galaxy/tool_util/version_updates.py
+++ b/lib/galaxy/tool_util/version_updates.py
@@ -6,9 +6,7 @@ tool definition for validation and state inspection.
"""
from typing import (
- Dict,
NamedTuple,
- Optional,
)
from .version import parse_version
@@ -20,7 +18,7 @@ class safe_update(NamedTuple):
current_version: AnyVersionT
-WORKFLOW_SAFE_TOOL_VERSION_UPDATES: Dict[str, safe_update] = {
+WORKFLOW_SAFE_TOOL_VERSION_UPDATES: dict[str, safe_update] = {
"Filter1": safe_update(parse_version("1.1.0"), parse_version("1.1.1")),
"__BUILD_LIST__": safe_update(parse_version("1.0.0"), parse_version("1.1.0")),
"__APPLY_RULES__": safe_update(parse_version("1.0.0"), parse_version("1.1.0")),
@@ -41,7 +39,7 @@ WORKFLOW_SAFE_TOOL_VERSION_UPDATES: Dict[str, safe_update] = {
}
-def is_workflow_safe_version(tool_id: str, requested_version: str) -> Optional[str]:
+def is_workflow_safe_version(tool_id: str, requested_version: str) -> str | None:
"""Check if requested_version falls within a safe update range for tool_id.
Returns the current_version string if safe, None otherwise.
diff --git a/lib/galaxy/tool_util/version_util.py b/lib/galaxy/tool_util/version_util.py
index 644d58297e4..b5291bfddad 100644
--- a/lib/galaxy/tool_util/version_util.py
+++ b/lib/galaxy/tool_util/version_util.py
@@ -1,10 +1,8 @@
-from typing import Union
-
from packaging.version import Version
from .version import LegacyVersion
-AnyVersionT = Union[LegacyVersion, Version]
+AnyVersionT = LegacyVersion | Version
__all__ = ["AnyVersionT"]
diff --git a/lib/galaxy/tool_util_models/__init__.py b/lib/galaxy/tool_util_models/__init__.py
index bde1138d6ac..35a506ee42c 100644
--- a/lib/galaxy/tool_util_models/__init__.py
+++ b/lib/galaxy/tool_util_models/__init__.py
@@ -6,13 +6,10 @@ for reasoning about tool state externally from Galaxy.
import re
from typing import (
+ Annotated,
Any,
ClassVar,
- Dict,
- List,
- Optional,
- Set,
- Tuple,
+ Literal,
Union,
)
@@ -32,8 +29,6 @@ from pydantic import (
)
from pydantic_core import PydanticCustomError
from typing_extensions import (
- Annotated,
- Literal,
NotRequired,
TypedDict,
)
@@ -69,7 +64,7 @@ from .tool_source import (
from .yaml_parameters import YamlGalaxyToolParameter
-def normalize_dict(values, keys: List[str]):
+def normalize_dict(values, keys: list[str]):
for key in keys:
items = values.get(key)
if isinstance(items, dict): # dict-of-dicts format
@@ -93,8 +88,8 @@ _TEMPLATE_BLOCK_RE = re.compile(r"\$\((.*?)\)", re.DOTALL)
_INPUTS_REF_RE = re.compile(r"\binputs\.([A-Za-z_][A-Za-z0-9_]*)")
-def _command_input_refs(text: Optional[str]) -> Set[str]:
- refs: Set[str] = set()
+def _command_input_refs(text: str | None) -> set[str]:
+ refs: set[str] = set()
if not text:
return refs
for block in _TEMPLATE_BLOCK_RE.findall(text):
@@ -103,14 +98,14 @@ def _command_input_refs(text: Optional[str]) -> Set[str]:
return refs
-def format_validation_errors(exc: ValidationError) -> List[str]:
+def format_validation_errors(exc: ValidationError) -> list[str]:
"""Distill a pydantic ValidationError into a human-readable list.
Each entry is `: `, or just `` for
model-level errors with no location. Suitable for surfacing directly to
a user (in the agent's bullet list, or as an API 4xx body).
"""
- lines: List[str] = []
+ lines: list[str] = []
for err in exc.errors():
loc_parts = [str(p) for p in err.get("loc", ()) if p not in ("__root__",)]
loc = ".".join(loc_parts)
@@ -128,7 +123,7 @@ class _DynamicToolSourceBase(ToolSourceBaseModel):
)
id: Annotated[
- Optional[str],
+ str | None,
Field(
description=(
"Unique identifier for the tool. Lowercase, must start with a letter, "
@@ -140,7 +135,7 @@ class _DynamicToolSourceBase(ToolSourceBaseModel):
pattern=TOOL_ID_PATTERN,
),
] = None
- version: Annotated[Optional[str], Field(description="Version for the tool.", examples=["0.1.0"])] = None
+ version: Annotated[str | None, Field(description="Version for the tool.", examples=["0.1.0"])] = None
name: Annotated[
str,
Field(
@@ -149,16 +144,16 @@ class _DynamicToolSourceBase(ToolSourceBaseModel):
),
]
description: Annotated[
- Optional[str],
+ str | None,
Field(
description="The description is displayed in the tool menu immediately following the hyperlink for the tool."
),
] = None
configfiles: Annotated[
- Optional[List[YamlTemplateConfigFile]], Field(description="A list of config files for this tool.")
+ list[YamlTemplateConfigFile] | None, Field(description="A list of config files for this tool.")
] = None
requirements: Annotated[
- Optional[List[Union[JavascriptRequirement, ResourceRequirement, ContainerRequirement]]],
+ list[JavascriptRequirement | ResourceRequirement | ContainerRequirement] | None,
Field(
description="A list of requirements needed to execute this tool. These can be javascript expressions, resource requirements or container images."
),
@@ -171,21 +166,21 @@ class _DynamicToolSourceBase(ToolSourceBaseModel):
examples=["head -n '$(inputs.num_lines)' '$(inputs.input_file.path)' > output.txt"],
),
]
- inputs: List[YamlGalaxyToolParameter] = []
- outputs: List[IncomingToolOutput] = []
- citations: Optional[List[Citation]] = None
+ inputs: list[YamlGalaxyToolParameter] = []
+ outputs: list[IncomingToolOutput] = []
+ citations: list[Citation] | None = None
license: Annotated[
- Optional[str],
+ str | None,
Field(
description="A full URI or a a short [SPDX](https://spdx.org/licenses/) identifier for a license for this tool wrapper. The tool wrapper license can be independent of the underlying tool license. This license covers the tool yaml and associated scripts shipped with the tool.",
examples=["MIT"],
),
] = None
- edam_operations: Optional[List[str]] = None
- edam_topics: Optional[List[str]] = None
- xrefs: Optional[List[XrefDict]] = None
- profile: Optional[float] = None
- help: Annotated[Optional[HelpContent], Field(description="Help text shown below the tool interface.")] = None
+ edam_operations: list[str] | None = None
+ edam_topics: list[str] | None = None
+ xrefs: list[XrefDict] | None = None
+ profile: float | None = None
+ help: Annotated[HelpContent | None, Field(description="Help text shown below the tool interface.")] = None
# NOTE: `tests` is intentionally NOT declared here. It lives on the concrete
# subclasses (`UserToolSource`, `YamlToolSource`) so that the slim
# `UserToolSourceAuthoringView` can inherit everything *except* the test
@@ -202,7 +197,7 @@ class _DynamicToolSourceBase(ToolSourceBaseModel):
@field_validator("name", "version", mode="after")
@classmethod
- def _reject_blank_strings(cls, v: Optional[str]) -> Optional[str]:
+ def _reject_blank_strings(cls, v: str | None) -> str | None:
if v is not None and not v.strip():
raise PydanticCustomError(
"dynamic_tool.blank_string",
@@ -212,12 +207,11 @@ class _DynamicToolSourceBase(ToolSourceBaseModel):
@model_validator(mode="after")
def _check_input_refs(self) -> "_DynamicToolSourceBase":
- declared_inputs: Set[str] = {param.root.name for param in self.inputs}
- referenced: Set[str] = _command_input_refs(self.shell_command)
+ declared_inputs: set[str] = {param.root.name for param in self.inputs}
+ referenced: set[str] = _command_input_refs(self.shell_command)
for configfile in self.configfiles or []:
referenced |= _command_input_refs(configfile.content)
- undeclared = sorted(referenced - declared_inputs)
- if undeclared:
+ if undeclared := sorted(referenced - declared_inputs):
joined = "; ".join(
f"references inputs.{name} but no input named '{name}' is declared" for name in undeclared
)
@@ -229,7 +223,7 @@ class _DynamicToolSourceBase(ToolSourceBaseModel):
@model_validator(mode="after")
def _check_output_claims(self) -> "_DynamicToolSourceBase":
- errors: List[str] = []
+ errors: list[str] = []
for output in self.outputs:
if isinstance(output, IncomingToolOutputDataset):
if not output.from_work_dir and not output.discover_datasets:
@@ -293,7 +287,7 @@ class UserToolSourceAuthoringView(_DynamicToolSourceBase):
# Field declaration order puts subclass fields (class_, container) after
# parent ones, which serializes them at the end. Re-order on dump so the
# YAML the tool editor renders leads with identity + runtime.
- _CANONICAL_FIELD_ORDER: ClassVar[Tuple[str, ...]] = (
+ _CANONICAL_FIELD_ORDER: ClassVar[tuple[str, ...]] = (
"class_",
"id",
"name",
@@ -337,7 +331,7 @@ class UserToolSourceAuthoringView(_DynamicToolSourceBase):
return data
by_alias = bool(getattr(info, "by_alias", False))
fields = type(self).model_fields
- ordered: Dict[str, Any] = {}
+ ordered: dict[str, Any] = {}
for field_name in self._CANONICAL_FIELD_ORDER:
field_info = fields.get(field_name)
key = (field_info.alias or field_name) if by_alias and field_info and field_info.alias else field_name
@@ -360,22 +354,22 @@ class UserToolSource(UserToolSourceAuthoringView):
# ``version`` is required (inherited from UserToolSourceAuthoringView). A stored
# row that predates the requirement won't validate; ``lift_user_tool_source``
# returns it as the raw dict with status "invalid" so its author still sees it.
- tests: Optional[List["YamlToolTest"]] = None
+ tests: list["YamlToolTest"] | None = None
class YamlToolSource(_DynamicToolSourceBase):
class_: Annotated[Literal["GalaxyTool"], Field(alias="class")]
container: Annotated[
- Optional[str],
+ str | None,
Field(
description="Container image to use for this tool.",
examples=["quay.io/biocontainers/python:3.13"],
),
] = None
- tests: Optional[List["YamlToolTest"]] = None
+ tests: list["YamlToolTest"] | None = None
-DynamicToolSources = Annotated[Union[UserToolSource, YamlToolSource], Field(discriminator="class_")]
+DynamicToolSources = Annotated[UserToolSource | YamlToolSource, Field(discriminator="class_")]
# ---------------------------------------------------------------------------
@@ -399,7 +393,7 @@ DynamicToolSources = Annotated[Union[UserToolSource, YamlToolSource], Field(disc
LiftStatus = Literal["ok", "lifted", "invalid"]
-def _navigable_path(value: Any, loc: tuple) -> Tuple[Optional[Any], List[Any]]:
+def _navigable_path(value: Any, loc: tuple) -> tuple[Any | None, list[Any]]:
"""Walk `loc` against the structure of `value`, skipping steps that don't
correspond to a real key/index (pydantic inserts discriminator literals
like `"data"` into the loc for tagged unions). Returns the parent
@@ -409,7 +403,7 @@ def _navigable_path(value: Any, loc: tuple) -> Tuple[Optional[Any], List[Any]]:
if not loc:
return cur, []
*prefix, leaf = loc
- cleaned: List[Any] = []
+ cleaned: list[Any] = []
for step in prefix:
if isinstance(cur, list) and isinstance(step, int) and 0 <= step < len(cur):
cur = cur[step]
@@ -433,8 +427,7 @@ def _strip_path(value: dict, loc: tuple) -> bool:
parent, cleaned = _navigable_path(value, loc)
if not cleaned or not isinstance(parent, dict):
return False
- leaf = cleaned[-1]
- if leaf in parent:
+ if (leaf := cleaned[-1]) in parent:
del parent[leaf]
return True
return False
@@ -442,7 +435,7 @@ def _strip_path(value: dict, loc: tuple) -> bool:
def lift_user_tool_source(
value: dict,
-) -> Tuple[LiftStatus, Union["UserToolSource", Dict[str, Any]], List[str]]:
+) -> tuple[LiftStatus, Union["UserToolSource", dict[str, Any]], list[str]]:
"""Validate `value` against the strict UserToolSource, lifting drift where
safe. See module docstring above for the contract.
"""
@@ -457,7 +450,7 @@ def lift_user_tool_source(
other = [err for err in errors if err.get("type") != "extra_forbidden"]
if extra_forbidden and not other:
stripped = copy.deepcopy(value)
- dropped: List[str] = []
+ dropped: list[str] = []
for err in extra_forbidden:
loc = tuple(err["loc"])
if _strip_path(stripped, loc):
@@ -473,29 +466,29 @@ def lift_user_tool_source(
class ParsedTool(ToolSourceBaseModel):
id: str
- version: Optional[str]
+ version: str | None
name: str
- description: Optional[str]
- requirements: List[
- Union[PackageRequirement, SetEnvironmentRequirement, ResourceRequirement, JavascriptRequirement]
- ] = Field(default_factory=list)
- containers: List[Container] = Field(default_factory=list)
+ description: str | None
+ requirements: list[PackageRequirement | SetEnvironmentRequirement | ResourceRequirement | JavascriptRequirement] = (
+ Field(default_factory=list)
+ )
+ containers: list[Container] = Field(default_factory=list)
stdio: Stdio = Field(default_factory=Stdio)
- inputs: List[ToolParameterT]
- outputs: List[ToolOutput]
- citations: List[Citation]
- license: Optional[str]
- profile: Optional[str]
- edam_operations: List[str]
- edam_topics: List[str]
- xrefs: List[XrefDict]
- help: Optional[HelpContent]
+ inputs: list[ToolParameterT]
+ outputs: list[ToolOutput]
+ citations: list[Citation]
+ license: str | None
+ profile: str | None
+ edam_operations: list[str]
+ edam_topics: list[str]
+ xrefs: list[XrefDict]
+ help: HelpContent | None
class BaseTestOutputModel(StrictModel):
model_config = ConfigDict(extra="forbid", title="BaseTestOutputModel")
file: Annotated[
- Optional[str],
+ str | None,
Field(
title="File",
description=(
@@ -505,11 +498,11 @@ class BaseTestOutputModel(StrictModel):
),
] = None
path: Annotated[
- Optional[str],
+ str | None,
Field(title="Path", description="Filesystem path to a local output file used for comparison."),
] = None
location: Annotated[
- Optional[AnyUrl],
+ AnyUrl | None,
Field(
title="Location",
description=(
@@ -521,7 +514,7 @@ class BaseTestOutputModel(StrictModel):
),
] = None
ftype: Annotated[
- Optional[str],
+ str | None,
Field(
title="File Type",
description=(
@@ -531,7 +524,7 @@ class BaseTestOutputModel(StrictModel):
),
] = None
sort: Annotated[
- Optional[bool],
+ bool | None,
Field(
title="Sort",
description=(
@@ -542,14 +535,14 @@ class BaseTestOutputModel(StrictModel):
),
] = None
compare: Annotated[
- Optional[OutputCompareType],
+ OutputCompareType | None,
Field(
title="Compare",
description="Comparison mode used when matching the output against the reference file.",
),
] = None
checksum: Annotated[
- Optional[str],
+ str | None,
Field(
title="Checksum",
description=(
@@ -560,18 +553,18 @@ class BaseTestOutputModel(StrictModel):
),
] = None
metadata: Annotated[
- Optional[Dict[str, Any]],
+ dict[str, Any] | None,
Field(
title="Metadata",
description="Mapping of metadata keys to expected values for this output.",
),
] = None
asserts: Annotated[
- Optional[assertions],
+ assertions | None,
Field(title="Asserts", description="Assertions about the content of the output."),
] = None
delta: Annotated[
- Optional[int],
+ int | None,
Field(
title="Delta",
description=(
@@ -582,7 +575,7 @@ class BaseTestOutputModel(StrictModel):
),
] = None
delta_frac: Annotated[
- Optional[float],
+ float | None,
Field(
title="Delta Frac",
description=(
@@ -594,7 +587,7 @@ class BaseTestOutputModel(StrictModel):
),
] = None
lines_diff: Annotated[
- Optional[int],
+ int | None,
Field(
title="Lines Diff",
description=(
@@ -605,7 +598,7 @@ class BaseTestOutputModel(StrictModel):
),
] = None
decompress: Annotated[
- Optional[bool],
+ bool | None,
Field(
title="Decompress",
description=(
@@ -621,25 +614,25 @@ class BaseTestOutputModel(StrictModel):
class TestDataOutputAssertions(BaseTestOutputModel):
model_config = ConfigDict(extra="forbid", title="TestDataOutputAssertions")
- class_: Optional[Literal["File"]] = Field("File", alias="class", title="Class")
+ class_: Literal["File"] | None = Field("File", alias="class", title="Class")
class TestCollectionCollectionElementAssertions(StrictModel):
model_config = ConfigDict(extra="forbid", title="TestCollectionCollectionElementAssertions")
- class_: Optional[Literal["Collection"]] = Field("Collection", alias="class", title="Class")
+ class_: Literal["Collection"] | None = Field("Collection", alias="class", title="Class")
elements: Annotated[
- Optional[Dict[str, "TestCollectionElementAssertion"]],
+ dict[str, "TestCollectionElementAssertion"] | None,
Field(title="Elements"),
] = None
element_tests: Annotated[
- Optional[Dict[str, "TestCollectionElementAssertion"]],
+ dict[str, "TestCollectionElementAssertion"] | None,
Field(title="Element Tests"),
] = None
class TestCollectionDatasetElementAssertions(BaseTestOutputModel):
model_config = ConfigDict(extra="forbid", title="TestCollectionDatasetElementAssertions")
- class_: Optional[Literal["File"]] = Field("File", alias="class", title="Class")
+ class_: Literal["File"] | None = Field("File", alias="class", title="Class")
def _discriminate_collection_element(v):
@@ -655,10 +648,8 @@ def _discriminate_collection_element(v):
TestCollectionElementAssertion = Annotated[
- Union[
- Annotated[TestCollectionDatasetElementAssertions, Tag("File")],
- Annotated[TestCollectionCollectionElementAssertions, Tag("Collection")],
- ],
+ Annotated[TestCollectionDatasetElementAssertions, Tag("File")]
+ | Annotated[TestCollectionCollectionElementAssertions, Tag("Collection")],
Discriminator(_discriminate_collection_element),
]
TestCollectionCollectionElementAssertions.model_rebuild()
@@ -671,21 +662,21 @@ class CollectionAttributes(StrictModel):
class TestCollectionOutputAssertions(StrictModel):
model_config = ConfigDict(extra="forbid", title="TestCollectionOutputAssertions")
- class_: Optional[Literal["Collection"]] = Field("Collection", alias="class", title="Class")
+ class_: Literal["Collection"] | None = Field("Collection", alias="class", title="Class")
elements: Annotated[
- Optional[Dict[str, TestCollectionElementAssertion]],
+ dict[str, TestCollectionElementAssertion] | None,
Field(title="Elements"),
] = None
element_tests: Annotated[
- Optional[Dict[str, "TestCollectionElementAssertion"]],
+ dict[str, "TestCollectionElementAssertion"] | None,
Field(title="Element Tests"),
] = None
- element_count: Annotated[Optional[int], Field(title="Element Count")] = None
- attributes: Annotated[Optional[CollectionAttributes], Field(title="Attributes")] = None
+ element_count: Annotated[int | None, Field(title="Element Count")] = None
+ attributes: Annotated[CollectionAttributes | None, Field(title="Attributes")] = None
collection_type: Annotated[CollectionType, Field(title="Collection Type")] = None
-TestOutputLiteral = Union[bool, int, float, str]
+TestOutputLiteral = bool | int | float | str
def _discriminate_output(v):
@@ -703,16 +694,14 @@ def _discriminate_output(v):
TestOutputAssertions = Annotated[
- Union[
- Annotated[TestCollectionOutputAssertions, Tag("Collection")],
- Annotated[TestDataOutputAssertions, Tag("File")],
- Annotated[TestOutputLiteral, Tag("scalar")],
- ],
+ Annotated[TestCollectionOutputAssertions, Tag("Collection")]
+ | Annotated[TestDataOutputAssertions, Tag("File")]
+ | Annotated[TestOutputLiteral, Tag("scalar")],
Discriminator(_discriminate_output),
]
-TestInputValue = Union[bool, int, float, str, List[Any], Dict[str, Any]]
+TestInputValue = bool | int | float | str | list[Any] | dict[str, Any]
class YamlTestCredentialValue(StrictModel):
@@ -725,15 +714,15 @@ class YamlTestCredential(StrictModel):
model_config = ConfigDict(extra="forbid", title="YamlTestCredential")
name: Annotated[str, Field(title="Name", description="Name of the credentials group.")]
variables: Annotated[
- List[YamlTestCredentialValue],
+ list[YamlTestCredentialValue],
Field(title="Variables", description="Variables exposed to the tool environment."),
] = []
secrets: Annotated[
- List[YamlTestCredentialValue],
+ list[YamlTestCredentialValue],
Field(title="Secrets", description="Secrets exposed to the tool environment."),
] = []
version: Annotated[
- Optional[str],
+ str | None,
Field(title="Version", description="Version of the credential definition."),
] = None
@@ -743,41 +732,41 @@ class YamlToolTest(BaseModel):
model_config = ConfigDict(extra="forbid")
- doc: Annotated[Optional[str], Field(description="Human-readable description of this test case.")] = None
+ doc: Annotated[str | None, Field(description="Human-readable description of this test case.")] = None
inputs: Annotated[
- Optional[Dict[str, TestInputValue]],
+ dict[str, TestInputValue] | None,
Field(description="Mapping of input parameter names to test values."),
] = None
outputs: Annotated[
- Dict[str, TestOutputAssertions],
+ dict[str, TestOutputAssertions],
Field(description="Mapping of output names to expected values or assertions."),
] = {}
assert_stdout: Annotated[
- Optional[assertions],
+ assertions | None,
Field(description="Assertions to apply against the tool's standard output."),
] = None
assert_stderr: Annotated[
- Optional[assertions],
+ assertions | None,
Field(description="Assertions to apply against the tool's standard error."),
] = None
command: Annotated[
- Optional[assertions],
+ assertions | None,
Field(description="Assertions to apply against the executed command line."),
] = None
expect_exit_code: Annotated[
- Optional[int],
+ int | None,
Field(description="Expected process exit code."),
] = None
expect_failure: Annotated[
- Optional[bool],
+ bool | None,
Field(description="If true, the tool is expected to produce an error."),
] = None
expect_test_failure: Annotated[
- Optional[bool],
+ bool | None,
Field(description="If true, the test itself is expected to fail."),
] = None
credentials: Annotated[
- Optional[List[YamlTestCredential]],
+ list[YamlTestCredential] | None,
Field(description="Credentials to inject for this test case."),
] = None
@@ -788,13 +777,13 @@ YamlToolSource.model_rebuild()
# Loose alias retained for TestJobDict / TypedDict consumers where helpers
# still tolerate Dict[str, Any]. The strict, validated shape is `Job` (see
# galaxy.tool_util_models.test_job).
-JobDict = Dict[str, Any]
+JobDict = dict[str, Any]
class TestJob(StrictModel):
model_config = ConfigDict(extra="forbid", title="TestJob")
doc: Annotated[
- Optional[str],
+ str | None,
Field(title="Doc", description="Describes the purpose of the test."),
] = None
job: Annotated[
@@ -802,13 +791,12 @@ class TestJob(StrictModel):
Field(
title="Job",
description=(
- "Defines the job to execute. Can be a path to a file or an inline dictionary describing "
- "the job inputs."
+ "Defines the job to execute. Can be a path to a file or an inline dictionary describing the job inputs."
),
),
]
outputs: Annotated[
- Dict[str, TestOutputAssertions],
+ dict[str, TestOutputAssertions],
Field(
title="Outputs",
description=(
@@ -818,7 +806,7 @@ class TestJob(StrictModel):
),
]
expect_failure: Annotated[
- Optional[bool],
+ bool | None,
Field(
title="Expect Failure",
description="If true, the workflow is expected to produce an error.",
@@ -826,7 +814,7 @@ class TestJob(StrictModel):
] = False
-class Tests(RootModel[List[TestJob]]):
+class Tests(RootModel[list[TestJob]]):
model_config = ConfigDict(
title="GalaxyWorkflowTests",
json_schema_extra={
@@ -841,8 +829,8 @@ class Tests(RootModel[List[TestJob]]):
# TODO: typed dict versions of all thee above for verify code - make this Dict[str, Any] here more
# specific.
-OutputChecks = Union[TestOutputLiteral, Dict[str, Any]]
-OutputsDict = Dict[str, OutputChecks]
+OutputChecks = TestOutputLiteral | dict[str, Any]
+OutputsDict = dict[str, OutputChecks]
class JobTestDict(TypedDict):
@@ -852,4 +840,4 @@ class JobTestDict(TypedDict):
outputs: OutputsDict
-TestDicts = List[JobTestDict]
+TestDicts = list[JobTestDict]
diff --git a/lib/galaxy/tool_util_models/_base.py b/lib/galaxy/tool_util_models/_base.py
index cf53028b625..28a3e240508 100644
--- a/lib/galaxy/tool_util_models/_base.py
+++ b/lib/galaxy/tool_util_models/_base.py
@@ -1,13 +1,12 @@
"""Base model classes for tool utilities."""
-from typing import Optional
+from typing import Annotated
from pydantic import (
AfterValidator,
BaseModel,
ConfigDict,
)
-from typing_extensions import Annotated
class ToolSourceBaseModel(BaseModel):
@@ -27,4 +26,4 @@ def _check_collection_type(v: str) -> str:
return v
-CollectionType = Annotated[Optional[str], AfterValidator(_check_collection_type)]
+CollectionType = Annotated[str | None, AfterValidator(_check_collection_type)]
diff --git a/lib/galaxy/tool_util_models/_types.py b/lib/galaxy/tool_util_models/_types.py
index c03a72cdb00..8aa63e31afc 100644
--- a/lib/galaxy/tool_util_models/_types.py
+++ b/lib/galaxy/tool_util_models/_types.py
@@ -5,58 +5,51 @@ are fine otherwise because we're using the typing system to interact with pydant
and build runtime models not to use mypy to type check static code.
"""
+from types import UnionType
from typing import (
+ Annotated,
Any,
cast,
- Dict,
- List,
- Optional,
- Type,
+ get_args,
+ get_origin,
+ TypeVar,
Union,
)
+
+def optional(type_: type) -> type:
+ return cast(type, type_ | None)
+
+
+def optional_if_needed(type_: type, is_optional: bool) -> type:
+ return optional(type_) if is_optional else type_
+
+
+def union_type(args: list[type]) -> type:
+ result = args[0]
+ for t in args[1:]:
+ result = cast(type, result | t)
+ return result
+
+
+T = TypeVar("T")
+
+
+def list_type(arg: type[T]) -> type[list[T]]:
+ return list[arg] # type: ignore[valid-type]
+
+
+def dict_type(key: type, val: type) -> type:
+ return dict[key, val] # type: ignore[valid-type]
+
+
# https://stackoverflow.com/questions/56832881/check-if-a-field-is-typing-optional
-from typing_extensions import (
- Annotated,
- get_args,
- get_origin,
-)
-
-
-def optional(type: Type) -> Type:
- return_type: Type = Optional[type] # type: ignore[assignment]
- return return_type
-
-
-def optional_if_needed(type: Type, is_optional: bool) -> Type:
- return_type: Type = type
- if is_optional:
- return_type = optional(type)
- return return_type
-
-
-def union_type(args: List[Type]) -> Type:
- return Union[tuple(args)] # type: ignore[return-value]
-
-
-def list_type(arg: Type) -> Type:
- return List[arg] # type: ignore[valid-type]
-
-
-def dict_type(key: Type, val: Type) -> Type:
- return Dict[key, val] # type: ignore[valid-type]
-
-
-def cast_as_type(arg) -> Type:
- return cast(Type, arg)
-
-
def is_optional(field) -> bool:
f = _strip_annotation(field)
if f == type(None): # noqa: E721
return True
origin = get_origin(f)
- if origin is Union:
+ if origin in (Union, UnionType):
return any(is_optional(f) for f in get_args(f))
return False
@@ -71,7 +64,7 @@ def _strip_annotation(field):
return field
-def expand_annotation(field: Type, new_annotations: List[Any]) -> Type:
+def expand_annotation(field: type, new_annotations: list[Any]) -> type:
is_annotation = get_origin(field) is Annotated
if is_annotation:
args = get_args(field) # noqa: F841
diff --git a/lib/galaxy/tool_util_models/assertions.py b/lib/galaxy/tool_util_models/assertions.py
index 5fc64425ab2..3d6e6d2f3c9 100644
--- a/lib/galaxy/tool_util_models/assertions.py
+++ b/lib/galaxy/tool_util_models/assertions.py
@@ -2,6 +2,10 @@
import re
import typing
+from typing import (
+ Annotated,
+ Literal,
+)
from pydantic import (
BaseModel,
@@ -13,10 +17,6 @@ from pydantic import (
StrictFloat,
StrictInt,
)
-from typing_extensions import (
- Annotated,
- Literal,
-)
BYTES_PATTERN = re.compile(r"^(0|[1-9][0-9]*)([kKMGTPE]i?)?$")
@@ -93,7 +93,7 @@ class base_has_line_model(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -102,16 +102,14 @@ class base_has_line_model(AssertionModel):
description=has_line_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_line_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -121,7 +119,7 @@ class base_has_line_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -130,7 +128,7 @@ class base_has_line_model(AssertionModel):
description=has_line_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_line_negate_description,
@@ -149,7 +147,7 @@ class base_has_line_model_relaxed(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -158,16 +156,14 @@ class base_has_line_model_relaxed(AssertionModel):
description=has_line_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_line_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -177,7 +173,7 @@ class base_has_line_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -186,7 +182,7 @@ class base_has_line_model_relaxed(AssertionModel):
description=has_line_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_line_negate_description,
@@ -245,7 +241,7 @@ class base_has_line_matching_model(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -254,16 +250,14 @@ class base_has_line_matching_model(AssertionModel):
description=has_line_matching_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_line_matching_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -273,7 +267,7 @@ class base_has_line_matching_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -282,7 +276,7 @@ class base_has_line_matching_model(AssertionModel):
description=has_line_matching_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_line_matching_negate_description,
@@ -301,7 +295,7 @@ class base_has_line_matching_model_relaxed(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -310,16 +304,14 @@ class base_has_line_matching_model_relaxed(AssertionModel):
description=has_line_matching_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_line_matching_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -329,7 +321,7 @@ class base_has_line_matching_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -338,7 +330,7 @@ class base_has_line_matching_model_relaxed(AssertionModel):
description=has_line_matching_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_line_matching_negate_description,
@@ -389,7 +381,7 @@ class base_has_n_lines_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_n_lines_model")
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -398,16 +390,14 @@ class base_has_n_lines_model(AssertionModel):
description=has_n_lines_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_n_lines_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -417,7 +407,7 @@ class base_has_n_lines_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -426,7 +416,7 @@ class base_has_n_lines_model(AssertionModel):
description=has_n_lines_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_n_lines_negate_description,
@@ -439,7 +429,7 @@ class base_has_n_lines_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_n_lines_model_relaxed")
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -448,16 +438,14 @@ class base_has_n_lines_model_relaxed(AssertionModel):
description=has_n_lines_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_n_lines_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -467,7 +455,7 @@ class base_has_n_lines_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -476,7 +464,7 @@ class base_has_n_lines_model_relaxed(AssertionModel):
description=has_n_lines_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_n_lines_negate_description,
@@ -535,7 +523,7 @@ class base_has_text_model(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -544,16 +532,14 @@ class base_has_text_model(AssertionModel):
description=has_text_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_text_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -563,7 +549,7 @@ class base_has_text_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -572,7 +558,7 @@ class base_has_text_model(AssertionModel):
description=has_text_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_text_negate_description,
@@ -591,7 +577,7 @@ class base_has_text_model_relaxed(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -600,16 +586,14 @@ class base_has_text_model_relaxed(AssertionModel):
description=has_text_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_text_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -619,7 +603,7 @@ class base_has_text_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -628,7 +612,7 @@ class base_has_text_model_relaxed(AssertionModel):
description=has_text_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_text_negate_description,
@@ -687,7 +671,7 @@ class base_has_text_matching_model(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -696,16 +680,14 @@ class base_has_text_matching_model(AssertionModel):
description=has_text_matching_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_text_matching_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -715,7 +697,7 @@ class base_has_text_matching_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -724,7 +706,7 @@ class base_has_text_matching_model(AssertionModel):
description=has_text_matching_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_text_matching_negate_description,
@@ -743,7 +725,7 @@ class base_has_text_matching_model_relaxed(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -752,16 +734,14 @@ class base_has_text_matching_model_relaxed(AssertionModel):
description=has_text_matching_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_text_matching_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -771,7 +751,7 @@ class base_has_text_matching_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -780,7 +760,7 @@ class base_has_text_matching_model_relaxed(AssertionModel):
description=has_text_matching_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_text_matching_negate_description,
@@ -889,7 +869,7 @@ class base_has_n_columns_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_n_columns_model")
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -898,16 +878,14 @@ class base_has_n_columns_model(AssertionModel):
description=has_n_columns_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_n_columns_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -917,7 +895,7 @@ class base_has_n_columns_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -938,7 +916,7 @@ class base_has_n_columns_model(AssertionModel):
description=has_n_columns_comment_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_n_columns_negate_description,
@@ -951,7 +929,7 @@ class base_has_n_columns_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_n_columns_model_relaxed")
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -960,16 +938,14 @@ class base_has_n_columns_model_relaxed(AssertionModel):
description=has_n_columns_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_n_columns_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -979,7 +955,7 @@ class base_has_n_columns_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1000,7 +976,7 @@ class base_has_n_columns_model_relaxed(AssertionModel):
description=has_n_columns_comment_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_n_columns_negate_description,
@@ -1078,7 +1054,7 @@ class base_attribute_is_model(AssertionModel):
description=attribute_is_text_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=attribute_is_negate_description,
@@ -1108,7 +1084,7 @@ class base_attribute_is_model_relaxed(AssertionModel):
description=attribute_is_text_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=attribute_is_negate_description,
@@ -1192,7 +1168,7 @@ class base_attribute_matches_model(AssertionModel):
description=attribute_matches_expression_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=attribute_matches_negate_description,
@@ -1222,7 +1198,7 @@ class base_attribute_matches_model_relaxed(AssertionModel):
description=attribute_matches_expression_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=attribute_matches_negate_description,
@@ -1288,7 +1264,7 @@ class base_element_text_model(AssertionModel):
description=element_text_path_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=element_text_negate_description,
@@ -1316,7 +1292,7 @@ class base_element_text_model_relaxed(AssertionModel):
description=element_text_path_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=element_text_negate_description,
@@ -1406,7 +1382,7 @@ class base_element_text_is_model(AssertionModel):
description=element_text_is_text_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=element_text_is_negate_description,
@@ -1430,7 +1406,7 @@ class base_element_text_is_model_relaxed(AssertionModel):
description=element_text_is_text_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=element_text_is_negate_description,
@@ -1506,7 +1482,7 @@ class base_element_text_matches_model(AssertionModel):
description=element_text_matches_expression_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=element_text_matches_negate_description,
@@ -1530,7 +1506,7 @@ class base_element_text_matches_model_relaxed(AssertionModel):
description=element_text_matches_expression_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=element_text_matches_negate_description,
@@ -1598,7 +1574,7 @@ class base_has_element_with_path_model(AssertionModel):
description=has_element_with_path_path_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_element_with_path_negate_description,
@@ -1616,7 +1592,7 @@ class base_has_element_with_path_model_relaxed(AssertionModel):
description=has_element_with_path_path_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_element_with_path_negate_description,
@@ -1691,7 +1667,7 @@ class base_has_n_elements_with_path_model(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1700,16 +1676,14 @@ class base_has_n_elements_with_path_model(AssertionModel):
description=has_n_elements_with_path_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_n_elements_with_path_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1719,7 +1693,7 @@ class base_has_n_elements_with_path_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1728,7 +1702,7 @@ class base_has_n_elements_with_path_model(AssertionModel):
description=has_n_elements_with_path_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_n_elements_with_path_negate_description,
@@ -1747,7 +1721,7 @@ class base_has_n_elements_with_path_model_relaxed(AssertionModel):
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1756,16 +1730,14 @@ class base_has_n_elements_with_path_model_relaxed(AssertionModel):
description=has_n_elements_with_path_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_n_elements_with_path_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1775,7 +1747,7 @@ class base_has_n_elements_with_path_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1784,7 +1756,7 @@ class base_has_n_elements_with_path_model_relaxed(AssertionModel):
description=has_n_elements_with_path_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_n_elements_with_path_negate_description,
@@ -1899,20 +1871,20 @@ class base_xml_element_model(AssertionModel):
description=xml_element_path_description,
)
- attribute: typing.Optional[typing.Union[str]] = Field(
+ attribute: str | None = Field(
None,
title="Attribute",
description=xml_element_attribute_description,
)
- all: typing.Union[bool, str] = Field(
+ all: bool | str = Field(
False,
title="All",
description=xml_element_all_description,
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1921,16 +1893,14 @@ class base_xml_element_model(AssertionModel):
description=xml_element_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=xml_element_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1940,7 +1910,7 @@ class base_xml_element_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1949,7 +1919,7 @@ class base_xml_element_model(AssertionModel):
description=xml_element_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=xml_element_negate_description,
@@ -1970,20 +1940,20 @@ class base_xml_element_model_relaxed(AssertionModel):
description=xml_element_path_description,
)
- attribute: typing.Optional[typing.Union[str]] = Field(
+ attribute: str | None = Field(
None,
title="Attribute",
description=xml_element_attribute_description,
)
- all: typing.Union[bool, str] = Field(
+ all: bool | str = Field(
False,
title="All",
description=xml_element_all_description,
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -1992,16 +1962,14 @@ class base_xml_element_model_relaxed(AssertionModel):
description=xml_element_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=xml_element_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2011,7 +1979,7 @@ class base_xml_element_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2020,7 +1988,7 @@ class base_xml_element_model_relaxed(AssertionModel):
description=xml_element_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=xml_element_negate_description,
@@ -2405,14 +2373,14 @@ class base_has_archive_member_model(AssertionModel):
description=has_archive_member_path_description,
)
- all: typing.Union[bool, str] = Field(
+ all: bool | str = Field(
False,
title="All",
description=has_archive_member_all_description,
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2421,16 +2389,14 @@ class base_has_archive_member_model(AssertionModel):
description=has_archive_member_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_archive_member_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2440,7 +2406,7 @@ class base_has_archive_member_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2449,7 +2415,7 @@ class base_has_archive_member_model(AssertionModel):
description=has_archive_member_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_archive_member_negate_description,
@@ -2470,14 +2436,14 @@ class base_has_archive_member_model_relaxed(AssertionModel):
description=has_archive_member_path_description,
)
- all: typing.Union[bool, str] = Field(
+ all: bool | str = Field(
False,
title="All",
description=has_archive_member_all_description,
)
n: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2486,16 +2452,14 @@ class base_has_archive_member_model_relaxed(AssertionModel):
description=has_archive_member_n_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_archive_member_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2505,7 +2469,7 @@ class base_has_archive_member_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2514,7 +2478,7 @@ class base_has_archive_member_model_relaxed(AssertionModel):
description=has_archive_member_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_archive_member_negate_description,
@@ -2652,7 +2616,7 @@ class base_has_size_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_size_model")
value: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2662,7 +2626,7 @@ class base_has_size_model(AssertionModel):
)
size: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2671,16 +2635,14 @@ class base_has_size_model(AssertionModel):
description=has_size_size_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_size_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2690,7 +2652,7 @@ class base_has_size_model(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2699,7 +2661,7 @@ class base_has_size_model(AssertionModel):
description=has_size_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_size_negate_description,
@@ -2712,7 +2674,7 @@ class base_has_size_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_size_model_relaxed")
value: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2722,7 +2684,7 @@ class base_has_size_model_relaxed(AssertionModel):
)
size: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2731,16 +2693,14 @@ class base_has_size_model_relaxed(AssertionModel):
description=has_size_size_description,
)
- delta: Annotated[
- typing.Union[int, str], BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)
- ] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_bytes), BeforeValidator(check_non_negative_if_int)] = Field(
0,
title="Delta",
description=has_size_delta_description,
)
min: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2750,7 +2710,7 @@ class base_has_size_model_relaxed(AssertionModel):
)
max: Annotated[
- typing.Optional[typing.Union[str, int]],
+ str | int | None,
BeforeValidator(check_bytes),
BeforeValidator(check_non_negative_if_int),
] = Field(
@@ -2759,7 +2719,7 @@ class base_has_size_model_relaxed(AssertionModel):
description=has_size_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_size_negate_description,
@@ -2819,25 +2779,25 @@ class base_has_image_center_of_mass_model(AssertionModel):
description=has_image_center_of_mass_center_of_mass_description,
)
- channel: typing.Optional[StrictInt] = Field(
+ channel: StrictInt | None = Field(
None,
title="Channel",
description=has_image_center_of_mass_channel_description,
)
- slice: typing.Optional[StrictInt] = Field(
+ slice: StrictInt | None = Field(
None,
title="Slice",
description=has_image_center_of_mass_slice_description,
)
- frame: typing.Optional[StrictInt] = Field(
+ frame: StrictInt | None = Field(
None,
title="Frame",
description=has_image_center_of_mass_frame_description,
)
- eps: Annotated[typing.Union[StrictInt, StrictFloat], BeforeValidator(check_non_negative_if_set)] = Field(
+ eps: Annotated[StrictInt | StrictFloat, BeforeValidator(check_non_negative_if_set)] = Field(
0.01,
title="Eps",
description=has_image_center_of_mass_eps_description,
@@ -2855,25 +2815,25 @@ class base_has_image_center_of_mass_model_relaxed(AssertionModel):
description=has_image_center_of_mass_center_of_mass_description,
)
- channel: typing.Optional[typing.Union[str, int]] = Field(
+ channel: str | int | None = Field(
None,
title="Channel",
description=has_image_center_of_mass_channel_description,
)
- slice: typing.Optional[typing.Union[str, int]] = Field(
+ slice: str | int | None = Field(
None,
title="Slice",
description=has_image_center_of_mass_slice_description,
)
- frame: typing.Optional[typing.Union[str, int]] = Field(
+ frame: str | int | None = Field(
None,
title="Frame",
description=has_image_center_of_mass_frame_description,
)
- eps: Annotated[typing.Union[float, str], BeforeValidator(check_non_negative_if_set)] = Field(
+ eps: Annotated[float | str, BeforeValidator(check_non_negative_if_set)] = Field(
0.01,
title="Eps",
description=has_image_center_of_mass_eps_description,
@@ -2925,7 +2885,7 @@ class base_has_image_channels_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_channels_model")
- channels: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ channels: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Channels",
description=has_image_channels_channels_description,
@@ -2937,19 +2897,19 @@ class base_has_image_channels_model(AssertionModel):
description=has_image_channels_delta_description,
)
- min: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_channels_min_description,
)
- max: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_channels_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_channels_negate_description,
@@ -2961,31 +2921,31 @@ class base_has_image_channels_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_channels_model_relaxed")
- channels: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ channels: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Channels",
description=has_image_channels_channels_description,
)
- delta: Annotated[typing.Union[int, str], BeforeValidator(check_non_negative_if_set)] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_non_negative_if_set)] = Field(
0,
title="Delta",
description=has_image_channels_delta_description,
)
- min: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_channels_min_description,
)
- max: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_channels_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_channels_negate_description,
@@ -3037,7 +2997,7 @@ class base_has_image_depth_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_depth_model")
- depth: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ depth: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Depth",
description=has_image_depth_depth_description,
@@ -3049,19 +3009,19 @@ class base_has_image_depth_model(AssertionModel):
description=has_image_depth_delta_description,
)
- min: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_depth_min_description,
)
- max: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_depth_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_depth_negate_description,
@@ -3073,31 +3033,31 @@ class base_has_image_depth_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_depth_model_relaxed")
- depth: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ depth: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Depth",
description=has_image_depth_depth_description,
)
- delta: Annotated[typing.Union[int, str], BeforeValidator(check_non_negative_if_set)] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_non_negative_if_set)] = Field(
0,
title="Delta",
description=has_image_depth_delta_description,
)
- min: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_depth_min_description,
)
- max: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_depth_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_depth_negate_description,
@@ -3147,7 +3107,7 @@ class base_has_image_frames_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_frames_model")
- frames: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ frames: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Frames",
description=has_image_frames_frames_description,
@@ -3159,19 +3119,19 @@ class base_has_image_frames_model(AssertionModel):
description=has_image_frames_delta_description,
)
- min: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_frames_min_description,
)
- max: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_frames_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_frames_negate_description,
@@ -3183,31 +3143,31 @@ class base_has_image_frames_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_frames_model_relaxed")
- frames: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ frames: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Frames",
description=has_image_frames_frames_description,
)
- delta: Annotated[typing.Union[int, str], BeforeValidator(check_non_negative_if_set)] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_non_negative_if_set)] = Field(
0,
title="Delta",
description=has_image_frames_delta_description,
)
- min: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_frames_min_description,
)
- max: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_frames_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_frames_negate_description,
@@ -3257,7 +3217,7 @@ class base_has_image_height_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_height_model")
- height: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ height: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Height",
description=has_image_height_height_description,
@@ -3269,19 +3229,19 @@ class base_has_image_height_model(AssertionModel):
description=has_image_height_delta_description,
)
- min: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_height_min_description,
)
- max: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_height_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_height_negate_description,
@@ -3293,31 +3253,31 @@ class base_has_image_height_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_height_model_relaxed")
- height: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ height: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Height",
description=has_image_height_height_description,
)
- delta: Annotated[typing.Union[int, str], BeforeValidator(check_non_negative_if_set)] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_non_negative_if_set)] = Field(
0,
title="Delta",
description=has_image_height_delta_description,
)
- min: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_height_min_description,
)
- max: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_height_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_height_negate_description,
@@ -3373,43 +3333,43 @@ class base_has_image_mean_intensity_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_mean_intensity_model")
- channel: typing.Optional[StrictInt] = Field(
+ channel: StrictInt | None = Field(
None,
title="Channel",
description=has_image_mean_intensity_channel_description,
)
- slice: typing.Optional[StrictInt] = Field(
+ slice: StrictInt | None = Field(
None,
title="Slice",
description=has_image_mean_intensity_slice_description,
)
- frame: typing.Optional[StrictInt] = Field(
+ frame: StrictInt | None = Field(
None,
title="Frame",
description=has_image_mean_intensity_frame_description,
)
- mean_intensity: typing.Optional[typing.Union[StrictInt, StrictFloat]] = Field(
+ mean_intensity: StrictInt | StrictFloat | None = Field(
None,
title="Mean Intensity",
description=has_image_mean_intensity_mean_intensity_description,
)
- eps: Annotated[typing.Union[StrictInt, StrictFloat], BeforeValidator(check_non_negative_if_set)] = Field(
+ eps: Annotated[StrictInt | StrictFloat, BeforeValidator(check_non_negative_if_set)] = Field(
0.01,
title="Eps",
description=has_image_mean_intensity_eps_description,
)
- min: typing.Optional[typing.Union[StrictInt, StrictFloat]] = Field(
+ min: StrictInt | StrictFloat | None = Field(
None,
title="Min",
description=has_image_mean_intensity_min_description,
)
- max: typing.Optional[typing.Union[StrictInt, StrictFloat]] = Field(
+ max: StrictInt | StrictFloat | None = Field(
None,
title="Max",
description=has_image_mean_intensity_max_description,
@@ -3421,43 +3381,43 @@ class base_has_image_mean_intensity_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_mean_intensity_model_relaxed")
- channel: typing.Optional[typing.Union[str, int]] = Field(
+ channel: str | int | None = Field(
None,
title="Channel",
description=has_image_mean_intensity_channel_description,
)
- slice: typing.Optional[typing.Union[str, int]] = Field(
+ slice: str | int | None = Field(
None,
title="Slice",
description=has_image_mean_intensity_slice_description,
)
- frame: typing.Optional[typing.Union[str, int]] = Field(
+ frame: str | int | None = Field(
None,
title="Frame",
description=has_image_mean_intensity_frame_description,
)
- mean_intensity: typing.Optional[typing.Union[float, str]] = Field(
+ mean_intensity: float | str | None = Field(
None,
title="Mean Intensity",
description=has_image_mean_intensity_mean_intensity_description,
)
- eps: Annotated[typing.Union[float, str], BeforeValidator(check_non_negative_if_set)] = Field(
+ eps: Annotated[float | str, BeforeValidator(check_non_negative_if_set)] = Field(
0.01,
title="Eps",
description=has_image_mean_intensity_eps_description,
)
- min: typing.Optional[typing.Union[float, str]] = Field(
+ min: float | str | None = Field(
None,
title="Min",
description=has_image_mean_intensity_min_description,
)
- max: typing.Optional[typing.Union[float, str]] = Field(
+ max: float | str | None = Field(
None,
title="Max",
description=has_image_mean_intensity_max_description,
@@ -3521,61 +3481,55 @@ class base_has_image_mean_object_size_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_mean_object_size_model")
- channel: typing.Optional[StrictInt] = Field(
+ channel: StrictInt | None = Field(
None,
title="Channel",
description=has_image_mean_object_size_channel_description,
)
- slice: typing.Optional[StrictInt] = Field(
+ slice: StrictInt | None = Field(
None,
title="Slice",
description=has_image_mean_object_size_slice_description,
)
- frame: typing.Optional[StrictInt] = Field(
+ frame: StrictInt | None = Field(
None,
title="Frame",
description=has_image_mean_object_size_frame_description,
)
- labels: typing.Optional[typing.List[typing.Union[StrictInt, StrictFloat]]] = Field(
+ labels: list[StrictInt | StrictFloat] | None = Field(
None,
title="Labels",
description=has_image_mean_object_size_labels_description,
)
- exclude_labels: typing.Optional[typing.List[typing.Union[StrictInt, StrictFloat]]] = Field(
+ exclude_labels: list[StrictInt | StrictFloat] | None = Field(
None,
title="Exclude Labels",
description=has_image_mean_object_size_exclude_labels_description,
)
- mean_object_size: Annotated[
- typing.Optional[typing.Union[StrictInt, StrictFloat]], BeforeValidator(check_non_negative_if_set)
- ] = Field(
+ mean_object_size: Annotated[StrictInt | StrictFloat | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Mean Object Size",
description=has_image_mean_object_size_mean_object_size_description,
)
- eps: Annotated[typing.Union[StrictInt, StrictFloat], BeforeValidator(check_non_negative_if_set)] = Field(
+ eps: Annotated[StrictInt | StrictFloat, BeforeValidator(check_non_negative_if_set)] = Field(
0.01,
title="Eps",
description=has_image_mean_object_size_eps_description,
)
- min: Annotated[
- typing.Optional[typing.Union[StrictInt, StrictFloat]], BeforeValidator(check_non_negative_if_set)
- ] = Field(
+ min: Annotated[StrictInt | StrictFloat | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_mean_object_size_min_description,
)
- max: Annotated[
- typing.Optional[typing.Union[StrictInt, StrictFloat]], BeforeValidator(check_non_negative_if_set)
- ] = Field(
+ max: Annotated[StrictInt | StrictFloat | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_mean_object_size_max_description,
@@ -3587,57 +3541,55 @@ class base_has_image_mean_object_size_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_mean_object_size_model_relaxed")
- channel: typing.Optional[typing.Union[str, int]] = Field(
+ channel: str | int | None = Field(
None,
title="Channel",
description=has_image_mean_object_size_channel_description,
)
- slice: typing.Optional[typing.Union[str, int]] = Field(
+ slice: str | int | None = Field(
None,
title="Slice",
description=has_image_mean_object_size_slice_description,
)
- frame: typing.Optional[typing.Union[str, int]] = Field(
+ frame: str | int | None = Field(
None,
title="Frame",
description=has_image_mean_object_size_frame_description,
)
- labels: typing.Optional[typing.Union[str, typing.List[typing.Union[float, int]]]] = Field(
+ labels: str | list[float | int] | None = Field(
None,
title="Labels",
description=has_image_mean_object_size_labels_description,
)
- exclude_labels: typing.Optional[typing.Union[str, typing.List[typing.Union[float, int]]]] = Field(
+ exclude_labels: str | list[float | int] | None = Field(
None,
title="Exclude Labels",
description=has_image_mean_object_size_exclude_labels_description,
)
- mean_object_size: Annotated[
- typing.Optional[typing.Union[float, str]], BeforeValidator(check_non_negative_if_set)
- ] = Field(
+ mean_object_size: Annotated[float | str | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Mean Object Size",
description=has_image_mean_object_size_mean_object_size_description,
)
- eps: Annotated[typing.Union[float, str], BeforeValidator(check_non_negative_if_set)] = Field(
+ eps: Annotated[float | str, BeforeValidator(check_non_negative_if_set)] = Field(
0.01,
title="Eps",
description=has_image_mean_object_size_eps_description,
)
- min: Annotated[typing.Optional[typing.Union[float, str]], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[float | str | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_mean_object_size_min_description,
)
- max: Annotated[typing.Optional[typing.Union[float, str]], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[float | str | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_mean_object_size_max_description,
@@ -3703,37 +3655,37 @@ class base_has_image_n_labels_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_n_labels_model")
- channel: typing.Optional[StrictInt] = Field(
+ channel: StrictInt | None = Field(
None,
title="Channel",
description=has_image_n_labels_channel_description,
)
- slice: typing.Optional[StrictInt] = Field(
+ slice: StrictInt | None = Field(
None,
title="Slice",
description=has_image_n_labels_slice_description,
)
- frame: typing.Optional[StrictInt] = Field(
+ frame: StrictInt | None = Field(
None,
title="Frame",
description=has_image_n_labels_frame_description,
)
- labels: typing.Optional[typing.List[typing.Union[StrictInt, StrictFloat]]] = Field(
+ labels: list[StrictInt | StrictFloat] | None = Field(
None,
title="Labels",
description=has_image_n_labels_labels_description,
)
- exclude_labels: typing.Optional[typing.List[typing.Union[StrictInt, StrictFloat]]] = Field(
+ exclude_labels: list[StrictInt | StrictFloat] | None = Field(
None,
title="Exclude Labels",
description=has_image_n_labels_exclude_labels_description,
)
- n: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ n: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="N",
description=has_image_n_labels_n_description,
@@ -3745,19 +3697,19 @@ class base_has_image_n_labels_model(AssertionModel):
description=has_image_n_labels_delta_description,
)
- min: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_n_labels_min_description,
)
- max: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_n_labels_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_n_labels_negate_description,
@@ -3769,61 +3721,61 @@ class base_has_image_n_labels_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_n_labels_model_relaxed")
- channel: typing.Optional[typing.Union[str, int]] = Field(
+ channel: str | int | None = Field(
None,
title="Channel",
description=has_image_n_labels_channel_description,
)
- slice: typing.Optional[typing.Union[str, int]] = Field(
+ slice: str | int | None = Field(
None,
title="Slice",
description=has_image_n_labels_slice_description,
)
- frame: typing.Optional[typing.Union[str, int]] = Field(
+ frame: str | int | None = Field(
None,
title="Frame",
description=has_image_n_labels_frame_description,
)
- labels: typing.Optional[typing.Union[str, typing.List[typing.Union[float, int]]]] = Field(
+ labels: str | list[float | int] | None = Field(
None,
title="Labels",
description=has_image_n_labels_labels_description,
)
- exclude_labels: typing.Optional[typing.Union[str, typing.List[typing.Union[float, int]]]] = Field(
+ exclude_labels: str | list[float | int] | None = Field(
None,
title="Exclude Labels",
description=has_image_n_labels_exclude_labels_description,
)
- n: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ n: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="N",
description=has_image_n_labels_n_description,
)
- delta: Annotated[typing.Union[int, str], BeforeValidator(check_non_negative_if_set)] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_non_negative_if_set)] = Field(
0,
title="Delta",
description=has_image_n_labels_delta_description,
)
- min: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_n_labels_min_description,
)
- max: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_n_labels_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_n_labels_negate_description,
@@ -3877,7 +3829,7 @@ class base_has_image_width_model(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_width_model")
- width: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ width: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Width",
description=has_image_width_width_description,
@@ -3889,19 +3841,19 @@ class base_has_image_width_model(AssertionModel):
description=has_image_width_delta_description,
)
- min: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_width_min_description,
)
- max: Annotated[typing.Optional[StrictInt], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[StrictInt | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_width_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_width_negate_description,
@@ -3913,31 +3865,31 @@ class base_has_image_width_model_relaxed(AssertionModel):
model_config = ConfigDict(extra="forbid", title="base_has_image_width_model_relaxed")
- width: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ width: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Width",
description=has_image_width_width_description,
)
- delta: Annotated[typing.Union[int, str], BeforeValidator(check_non_negative_if_set)] = Field(
+ delta: Annotated[int | str, BeforeValidator(check_non_negative_if_set)] = Field(
0,
title="Delta",
description=has_image_width_delta_description,
)
- min: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ min: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Min",
description=has_image_width_min_description,
)
- max: Annotated[typing.Optional[typing.Union[str, int]], BeforeValidator(check_non_negative_if_set)] = Field(
+ max: Annotated[str | int | None, BeforeValidator(check_non_negative_if_set)] = Field(
None,
title="Max",
description=has_image_width_max_description,
)
- negate: typing.Union[bool, str] = Field(
+ negate: bool | str = Field(
False,
title="Negate",
description=has_image_width_negate_description,
@@ -3972,204 +3924,196 @@ class has_image_width_model_relaxed(base_has_image_width_model_relaxed):
any_assertion_model_flat = Annotated[
- typing.Union[
- has_line_model,
- has_line_matching_model,
- has_n_lines_model,
- has_text_model,
- has_text_matching_model,
- not_has_text_model,
- has_n_columns_model,
- attribute_is_model,
- attribute_matches_model,
- element_text_model,
- element_text_is_model,
- element_text_matches_model,
- has_element_with_path_model,
- has_n_elements_with_path_model,
- is_valid_xml_model,
- xml_element_model,
- has_json_property_with_text_model,
- has_json_property_with_value_model,
- has_h5_attribute_model,
- has_h5_keys_model,
- has_archive_member_model,
- has_size_model,
- has_image_center_of_mass_model,
- has_image_channels_model,
- has_image_depth_model,
- has_image_frames_model,
- has_image_height_model,
- has_image_mean_intensity_model,
- has_image_mean_object_size_model,
- has_image_n_labels_model,
- has_image_width_model,
- ],
+ has_line_model
+ | has_line_matching_model
+ | has_n_lines_model
+ | has_text_model
+ | has_text_matching_model
+ | not_has_text_model
+ | has_n_columns_model
+ | attribute_is_model
+ | attribute_matches_model
+ | element_text_model
+ | element_text_is_model
+ | element_text_matches_model
+ | has_element_with_path_model
+ | has_n_elements_with_path_model
+ | is_valid_xml_model
+ | xml_element_model
+ | has_json_property_with_text_model
+ | has_json_property_with_value_model
+ | has_h5_attribute_model
+ | has_h5_keys_model
+ | has_archive_member_model
+ | has_size_model
+ | has_image_center_of_mass_model
+ | has_image_channels_model
+ | has_image_depth_model
+ | has_image_frames_model
+ | has_image_height_model
+ | has_image_mean_intensity_model
+ | has_image_mean_object_size_model
+ | has_image_n_labels_model
+ | has_image_width_model,
Field(discriminator="that"),
]
-any_assertion_model_nested = typing.Union[
- has_line_model_nested,
- has_line_matching_model_nested,
- has_n_lines_model_nested,
- has_text_model_nested,
- has_text_matching_model_nested,
- not_has_text_model_nested,
- has_n_columns_model_nested,
- attribute_is_model_nested,
- attribute_matches_model_nested,
- element_text_model_nested,
- element_text_is_model_nested,
- element_text_matches_model_nested,
- has_element_with_path_model_nested,
- has_n_elements_with_path_model_nested,
- is_valid_xml_model_nested,
- xml_element_model_nested,
- has_json_property_with_text_model_nested,
- has_json_property_with_value_model_nested,
- has_h5_attribute_model_nested,
- has_h5_keys_model_nested,
- has_archive_member_model_nested,
- has_size_model_nested,
- has_image_center_of_mass_model_nested,
- has_image_channels_model_nested,
- has_image_depth_model_nested,
- has_image_frames_model_nested,
- has_image_height_model_nested,
- has_image_mean_intensity_model_nested,
- has_image_mean_object_size_model_nested,
- has_image_n_labels_model_nested,
- has_image_width_model_nested,
-]
+any_assertion_model_nested = (
+ has_line_model_nested
+ | has_line_matching_model_nested
+ | has_n_lines_model_nested
+ | has_text_model_nested
+ | has_text_matching_model_nested
+ | not_has_text_model_nested
+ | has_n_columns_model_nested
+ | attribute_is_model_nested
+ | attribute_matches_model_nested
+ | element_text_model_nested
+ | element_text_is_model_nested
+ | element_text_matches_model_nested
+ | has_element_with_path_model_nested
+ | has_n_elements_with_path_model_nested
+ | is_valid_xml_model_nested
+ | xml_element_model_nested
+ | has_json_property_with_text_model_nested
+ | has_json_property_with_value_model_nested
+ | has_h5_attribute_model_nested
+ | has_h5_keys_model_nested
+ | has_archive_member_model_nested
+ | has_size_model_nested
+ | has_image_center_of_mass_model_nested
+ | has_image_channels_model_nested
+ | has_image_depth_model_nested
+ | has_image_frames_model_nested
+ | has_image_height_model_nested
+ | has_image_mean_intensity_model_nested
+ | has_image_mean_object_size_model_nested
+ | has_image_n_labels_model_nested
+ | has_image_width_model_nested
+)
any_assertion_model_flat_relaxed = Annotated[
- typing.Union[
- has_line_model_relaxed,
- has_line_matching_model_relaxed,
- has_n_lines_model_relaxed,
- has_text_model_relaxed,
- has_text_matching_model_relaxed,
- not_has_text_model_relaxed,
- has_n_columns_model_relaxed,
- attribute_is_model_relaxed,
- attribute_matches_model_relaxed,
- element_text_model_relaxed,
- element_text_is_model_relaxed,
- element_text_matches_model_relaxed,
- has_element_with_path_model_relaxed,
- has_n_elements_with_path_model_relaxed,
- is_valid_xml_model_relaxed,
- xml_element_model_relaxed,
- has_json_property_with_text_model_relaxed,
- has_json_property_with_value_model_relaxed,
- has_h5_attribute_model_relaxed,
- has_h5_keys_model_relaxed,
- has_archive_member_model_relaxed,
- has_size_model_relaxed,
- has_image_center_of_mass_model_relaxed,
- has_image_channels_model_relaxed,
- has_image_depth_model_relaxed,
- has_image_frames_model_relaxed,
- has_image_height_model_relaxed,
- has_image_mean_intensity_model_relaxed,
- has_image_mean_object_size_model_relaxed,
- has_image_n_labels_model_relaxed,
- has_image_width_model_relaxed,
- ],
+ has_line_model_relaxed
+ | has_line_matching_model_relaxed
+ | has_n_lines_model_relaxed
+ | has_text_model_relaxed
+ | has_text_matching_model_relaxed
+ | not_has_text_model_relaxed
+ | has_n_columns_model_relaxed
+ | attribute_is_model_relaxed
+ | attribute_matches_model_relaxed
+ | element_text_model_relaxed
+ | element_text_is_model_relaxed
+ | element_text_matches_model_relaxed
+ | has_element_with_path_model_relaxed
+ | has_n_elements_with_path_model_relaxed
+ | is_valid_xml_model_relaxed
+ | xml_element_model_relaxed
+ | has_json_property_with_text_model_relaxed
+ | has_json_property_with_value_model_relaxed
+ | has_h5_attribute_model_relaxed
+ | has_h5_keys_model_relaxed
+ | has_archive_member_model_relaxed
+ | has_size_model_relaxed
+ | has_image_center_of_mass_model_relaxed
+ | has_image_channels_model_relaxed
+ | has_image_depth_model_relaxed
+ | has_image_frames_model_relaxed
+ | has_image_height_model_relaxed
+ | has_image_mean_intensity_model_relaxed
+ | has_image_mean_object_size_model_relaxed
+ | has_image_n_labels_model_relaxed
+ | has_image_width_model_relaxed,
Field(discriminator="that"),
]
-class assertion_list(RootModel[typing.List[typing.Union[any_assertion_model_flat, any_assertion_model_nested]]]):
+class assertion_list(RootModel[list[any_assertion_model_flat | any_assertion_model_nested]]):
model_config = ConfigDict(title="assertion_list")
# used to model what the XML conversion should look like - not meant to be consumed outside of
# of Galaxy internals / linting.
-class relaxed_assertion_list(RootModel[typing.List[any_assertion_model_flat_relaxed]]):
+class relaxed_assertion_list(RootModel[list[any_assertion_model_flat_relaxed]]):
model_config = ConfigDict(title="relaxed_assertion_list")
class assertion_dict(AssertionModel):
model_config = ConfigDict(extra="forbid", title="assertion_dict")
- has_line: typing.Optional[base_has_line_model] = Field(None, title="Assert Has Line")
+ has_line: base_has_line_model | None = Field(None, title="Assert Has Line")
- has_line_matching: typing.Optional[base_has_line_matching_model] = Field(None, title="Assert Has Line Matching")
+ has_line_matching: base_has_line_matching_model | None = Field(None, title="Assert Has Line Matching")
- has_n_lines: typing.Optional[base_has_n_lines_model] = Field(None, title="Assert Has N Lines")
+ has_n_lines: base_has_n_lines_model | None = Field(None, title="Assert Has N Lines")
- has_text: typing.Optional[base_has_text_model] = Field(None, title="Assert Has Text")
+ has_text: base_has_text_model | None = Field(None, title="Assert Has Text")
- has_text_matching: typing.Optional[base_has_text_matching_model] = Field(None, title="Assert Has Text Matching")
+ has_text_matching: base_has_text_matching_model | None = Field(None, title="Assert Has Text Matching")
- not_has_text: typing.Optional[base_not_has_text_model] = Field(None, title="Assert Not Has Text")
+ not_has_text: base_not_has_text_model | None = Field(None, title="Assert Not Has Text")
- has_n_columns: typing.Optional[base_has_n_columns_model] = Field(None, title="Assert Has N Columns")
+ has_n_columns: base_has_n_columns_model | None = Field(None, title="Assert Has N Columns")
- attribute_is: typing.Optional[base_attribute_is_model] = Field(None, title="Assert Attribute Is")
+ attribute_is: base_attribute_is_model | None = Field(None, title="Assert Attribute Is")
- attribute_matches: typing.Optional[base_attribute_matches_model] = Field(None, title="Assert Attribute Matches")
+ attribute_matches: base_attribute_matches_model | None = Field(None, title="Assert Attribute Matches")
- element_text: typing.Optional[base_element_text_model] = Field(None, title="Assert Element Text")
+ element_text: base_element_text_model | None = Field(None, title="Assert Element Text")
- element_text_is: typing.Optional[base_element_text_is_model] = Field(None, title="Assert Element Text Is")
+ element_text_is: base_element_text_is_model | None = Field(None, title="Assert Element Text Is")
- element_text_matches: typing.Optional[base_element_text_matches_model] = Field(
- None, title="Assert Element Text Matches"
- )
+ element_text_matches: base_element_text_matches_model | None = Field(None, title="Assert Element Text Matches")
- has_element_with_path: typing.Optional[base_has_element_with_path_model] = Field(
- None, title="Assert Has Element With Path"
- )
+ has_element_with_path: base_has_element_with_path_model | None = Field(None, title="Assert Has Element With Path")
- has_n_elements_with_path: typing.Optional[base_has_n_elements_with_path_model] = Field(
+ has_n_elements_with_path: base_has_n_elements_with_path_model | None = Field(
None, title="Assert Has N Elements With Path"
)
- is_valid_xml: typing.Optional[base_is_valid_xml_model] = Field(None, title="Assert Is Valid Xml")
+ is_valid_xml: base_is_valid_xml_model | None = Field(None, title="Assert Is Valid Xml")
- xml_element: typing.Optional[base_xml_element_model] = Field(None, title="Assert Xml Element")
+ xml_element: base_xml_element_model | None = Field(None, title="Assert Xml Element")
- has_json_property_with_text: typing.Optional[base_has_json_property_with_text_model] = Field(
+ has_json_property_with_text: base_has_json_property_with_text_model | None = Field(
None, title="Assert Has Json Property With Text"
)
- has_json_property_with_value: typing.Optional[base_has_json_property_with_value_model] = Field(
+ has_json_property_with_value: base_has_json_property_with_value_model | None = Field(
None, title="Assert Has Json Property With Value"
)
- has_h5_attribute: typing.Optional[base_has_h5_attribute_model] = Field(None, title="Assert Has H5 Attribute")
+ has_h5_attribute: base_has_h5_attribute_model | None = Field(None, title="Assert Has H5 Attribute")
- has_h5_keys: typing.Optional[base_has_h5_keys_model] = Field(None, title="Assert Has H5 Keys")
+ has_h5_keys: base_has_h5_keys_model | None = Field(None, title="Assert Has H5 Keys")
- has_archive_member: typing.Optional[base_has_archive_member_model] = Field(None, title="Assert Has Archive Member")
+ has_archive_member: base_has_archive_member_model | None = Field(None, title="Assert Has Archive Member")
- has_size: typing.Optional[base_has_size_model] = Field(None, title="Assert Has Size")
+ has_size: base_has_size_model | None = Field(None, title="Assert Has Size")
- has_image_center_of_mass: typing.Optional[base_has_image_center_of_mass_model] = Field(
+ has_image_center_of_mass: base_has_image_center_of_mass_model | None = Field(
None, title="Assert Has Image Center Of Mass"
)
- has_image_channels: typing.Optional[base_has_image_channels_model] = Field(None, title="Assert Has Image Channels")
+ has_image_channels: base_has_image_channels_model | None = Field(None, title="Assert Has Image Channels")
- has_image_depth: typing.Optional[base_has_image_depth_model] = Field(None, title="Assert Has Image Depth")
+ has_image_depth: base_has_image_depth_model | None = Field(None, title="Assert Has Image Depth")
- has_image_frames: typing.Optional[base_has_image_frames_model] = Field(None, title="Assert Has Image Frames")
+ has_image_frames: base_has_image_frames_model | None = Field(None, title="Assert Has Image Frames")
- has_image_height: typing.Optional[base_has_image_height_model] = Field(None, title="Assert Has Image Height")
+ has_image_height: base_has_image_height_model | None = Field(None, title="Assert Has Image Height")
- has_image_mean_intensity: typing.Optional[base_has_image_mean_intensity_model] = Field(
+ has_image_mean_intensity: base_has_image_mean_intensity_model | None = Field(
None, title="Assert Has Image Mean Intensity"
)
- has_image_mean_object_size: typing.Optional[base_has_image_mean_object_size_model] = Field(
+ has_image_mean_object_size: base_has_image_mean_object_size_model | None = Field(
None, title="Assert Has Image Mean Object Size"
)
- has_image_n_labels: typing.Optional[base_has_image_n_labels_model] = Field(None, title="Assert Has Image N Labels")
+ has_image_n_labels: base_has_image_n_labels_model | None = Field(None, title="Assert Has Image N Labels")
- has_image_width: typing.Optional[base_has_image_width_model] = Field(None, title="Assert Has Image Width")
+ has_image_width: base_has_image_width_model | None = Field(None, title="Assert Has Image Width")
-assertions = typing.Union[assertion_list, assertion_dict]
+assertions = assertion_list | assertion_dict
diff --git a/lib/galaxy/tool_util_models/dynamic_tool_models.py b/lib/galaxy/tool_util_models/dynamic_tool_models.py
index d6d1a9a1cfd..d340ab48a40 100644
--- a/lib/galaxy/tool_util_models/dynamic_tool_models.py
+++ b/lib/galaxy/tool_util_models/dynamic_tool_models.py
@@ -1,10 +1,6 @@
-from typing import (
- Optional,
- Union,
-)
+from typing import Literal
from pydantic import BaseModel
-from typing_extensions import Literal
from galaxy.tool_util_models import (
DynamicToolSources,
@@ -13,15 +9,15 @@ from galaxy.tool_util_models import (
class BaseDynamicToolCreatePayload(BaseModel):
- active: Optional[bool] = None
- hidden: Optional[bool] = None
+ active: bool | None = None
+ hidden: bool | None = None
class DynamicToolCreatePayload(BaseDynamicToolCreatePayload):
src: Literal["representation"] = "representation"
representation: DynamicToolSources
- active: Optional[bool] = True
- hidden: Optional[bool] = False
+ active: bool | None = True
+ hidden: bool | None = False
class DynamicUnprivilegedToolCreatePayload(DynamicToolCreatePayload):
@@ -31,7 +27,7 @@ class DynamicUnprivilegedToolCreatePayload(DynamicToolCreatePayload):
class PathBasedDynamicToolCreatePayload(BaseDynamicToolCreatePayload):
src: Literal["from_path"]
path: str
- tool_directory: Optional[str] = None
+ tool_directory: str | None = None
-DynamicToolPayload = Union[DynamicToolCreatePayload, PathBasedDynamicToolCreatePayload]
+DynamicToolPayload = DynamicToolCreatePayload | PathBasedDynamicToolCreatePayload
diff --git a/lib/galaxy/tool_util_models/parameter_validators.py b/lib/galaxy/tool_util_models/parameter_validators.py
index 20eebaad333..4ad2c638470 100644
--- a/lib/galaxy/tool_util_models/parameter_validators.py
+++ b/lib/galaxy/tool_util_models/parameter_validators.py
@@ -1,8 +1,7 @@
from typing import (
+ Annotated,
Any,
- List,
- Optional,
- Union,
+ Literal,
)
from pydantic import (
@@ -14,8 +13,6 @@ from pydantic import (
TypeAdapter,
)
from typing_extensions import (
- Annotated,
- Literal,
Protocol,
Self,
)
@@ -27,13 +24,13 @@ except ImportError:
class ValidationArgument:
- doc: Optional[str]
+ doc: str | None
xml_body: bool
xml_allow_json_load: bool
def __init__(
self,
- doc: Optional[str],
+ doc: str | None,
xml_body: bool = False,
xml_allow_json_load: bool = False,
):
@@ -73,12 +70,11 @@ ValidatorType = Literal[
class ValidatorDescription(Protocol):
-
@property
def negate(self) -> bool: ...
@property
- def message(self) -> Optional[str]: ...
+ def message(self) -> str | None: ...
class StrictModel(BaseModel):
@@ -88,7 +84,7 @@ class StrictModel(BaseModel):
class ParameterValidatorModel(StrictModel):
type: ValidatorType
message: Annotated[
- Optional[str],
+ str | None,
ValidationArgument(
"""The error message displayed on the tool form if validation fails. A placeholder string ``%s`` will be repaced by the ``value``"""
),
@@ -131,7 +127,7 @@ class ExpressionParameterValidatorModel(StaticValidatorModel):
ExpressionParameterValidatorModel.expression_validation(self.expression, value, self)
@staticmethod
- def ensure_compiled(expression: Union[str, Any]) -> Any:
+ def ensure_compiled(expression: str | Any) -> Any:
if isinstance(expression, str):
return compile(expression, "", "eval")
else:
@@ -139,7 +135,7 @@ class ExpressionParameterValidatorModel(StaticValidatorModel):
@staticmethod
def expression_validation(
- expression: str, value: Any, validator: "ValidatorDescription", compiled_expression: Optional[Any] = None
+ expression: str, value: Any, validator: "ValidatorDescription", compiled_expression: Any | None = None
):
if compiled_expression is None:
compiled_expression = ExpressionParameterValidatorModel.ensure_compiled(expression)
@@ -189,8 +185,8 @@ class RegexParameterValidatorModel(StaticValidatorModel):
class InRangeParameterValidatorModel(StaticValidatorModel):
type: Literal["in_range"] = "in_range"
- min: Optional[Union[float, int]] = None
- max: Optional[Union[float, int]] = None
+ min: float | int | None = None
+ max: float | int | None = None
exclude_min: bool = False
exclude_max: bool = False
negate: Negate = NEGATE_DEFAULT
@@ -225,8 +221,8 @@ class InRangeParameterValidatorModel(StaticValidatorModel):
class LengthParameterValidatorModel(StaticValidatorModel):
type: Literal["length"] = "length"
- min: Optional[int] = None
- max: Optional[int] = None
+ min: int | None = None
+ max: int | None = None
negate: Negate = NEGATE_DEFAULT
_safe: bool = PrivateAttr(True)
@@ -247,8 +243,8 @@ class LengthParameterValidatorModel(StaticValidatorModel):
class MetadataParameterValidatorModel(ParameterValidatorModel):
type: Literal["metadata"] = "metadata"
- check: Optional[List[str]] = None
- skip: Optional[List[str]] = None
+ check: list[str] | None = None
+ skip: list[str] | None = None
negate: Negate = NEGATE_DEFAULT
@property
@@ -349,7 +345,7 @@ class DatasetMetadataInDataTableParameterValidatorModel(ParameterValidatorModel)
type: Literal["dataset_metadata_in_data_table"] = "dataset_metadata_in_data_table"
table_name: str
metadata_name: str
- metadata_column: Union[int, str]
+ metadata_column: int | str
negate: Negate = NEGATE_DEFAULT
@property
@@ -361,7 +357,7 @@ class DatasetMetadataNotInDataTableParameterValidatorModel(ParameterValidatorMod
type: Literal["dataset_metadata_not_in_data_table"] = "dataset_metadata_not_in_data_table"
table_name: str
metadata_name: str
- metadata_column: Union[int, str]
+ metadata_column: int | str
negate: Negate = NEGATE_DEFAULT
@property
@@ -372,8 +368,8 @@ class DatasetMetadataNotInDataTableParameterValidatorModel(ParameterValidatorMod
class DatasetMetadataInRangeParameterValidatorModel(ParameterValidatorModel):
type: Literal["dataset_metadata_in_range"] = "dataset_metadata_in_range"
metadata_name: str
- min: Optional[Union[float, int]] = None
- max: Optional[Union[float, int]] = None
+ min: float | int | None = None
+ max: float | int | None = None
exclude_min: bool = False
exclude_max: bool = False
negate: Negate = NEGATE_DEFAULT
@@ -393,7 +389,7 @@ class DatasetMetadataInRangeParameterValidatorModel(ParameterValidatorModel):
class ValueInDataTableParameterValidatorModel(ParameterValidatorModel):
type: Literal["value_in_data_table"] = "value_in_data_table"
table_name: str
- metadata_column: Union[int, str]
+ metadata_column: int | str
negate: Negate = NEGATE_DEFAULT
@property
@@ -404,7 +400,7 @@ class ValueInDataTableParameterValidatorModel(ParameterValidatorModel):
class ValueNotInDataTableParameterValidatorModel(ParameterValidatorModel):
type: Literal["value_not_in_data_table"] = "value_not_in_data_table"
table_name: str
- metadata_column: Union[int, str]
+ metadata_column: int | str
negate: Negate = NEGATE_DEFAULT
@property
@@ -431,8 +427,8 @@ class DatasetMetadataInFileParameterValidatorModel(ParameterValidatorModel):
type: Literal["dataset_metadata_in_file"] = "dataset_metadata_in_file"
filename: str
metadata_name: str
- metadata_column: Union[int, str]
- line_startswith: Optional[str] = None
+ metadata_column: int | str
+ line_startswith: str | None = None
split: str = SPLIT_DEFAULT
negate: Negate = NEGATE_DEFAULT
_deprecated: bool = PrivateAttr(True)
@@ -443,35 +439,29 @@ class DatasetMetadataInFileParameterValidatorModel(ParameterValidatorModel):
AnyValidatorModel = Annotated[
- Union[
- ExpressionParameterValidatorModel,
- RegexParameterValidatorModel,
- InRangeParameterValidatorModel,
- LengthParameterValidatorModel,
- MetadataParameterValidatorModel,
- DatasetMetadataEqualParameterValidatorModel,
- UnspecifiedBuildParameterValidatorModel,
- NoOptionsParameterValidatorModel,
- EmptyFieldParameterValidatorModel,
- EmptyDatasetParameterValidatorModel,
- EmptyExtraFilesPathParameterValidatorModel,
- DatasetMetadataInDataTableParameterValidatorModel,
- DatasetMetadataNotInDataTableParameterValidatorModel,
- DatasetMetadataInRangeParameterValidatorModel,
- ValueInDataTableParameterValidatorModel,
- ValueNotInDataTableParameterValidatorModel,
- DatasetOkValidatorParameterValidatorModel,
- DatasetMetadataInFileParameterValidatorModel,
- ],
+ ExpressionParameterValidatorModel
+ | RegexParameterValidatorModel
+ | InRangeParameterValidatorModel
+ | LengthParameterValidatorModel
+ | MetadataParameterValidatorModel
+ | DatasetMetadataEqualParameterValidatorModel
+ | UnspecifiedBuildParameterValidatorModel
+ | NoOptionsParameterValidatorModel
+ | EmptyFieldParameterValidatorModel
+ | EmptyDatasetParameterValidatorModel
+ | EmptyExtraFilesPathParameterValidatorModel
+ | DatasetMetadataInDataTableParameterValidatorModel
+ | DatasetMetadataNotInDataTableParameterValidatorModel
+ | DatasetMetadataInRangeParameterValidatorModel
+ | ValueInDataTableParameterValidatorModel
+ | ValueNotInDataTableParameterValidatorModel
+ | DatasetOkValidatorParameterValidatorModel
+ | DatasetMetadataInFileParameterValidatorModel,
Field(discriminator="type"),
]
AnySafeValidatorModel = Annotated[
- Union[
- RegexParameterValidatorModel,
- InRangeParameterValidatorModel,
- LengthParameterValidatorModel,
- ],
+ RegexParameterValidatorModel | InRangeParameterValidatorModel | LengthParameterValidatorModel,
Field(discriminator="type"),
]
@@ -480,7 +470,7 @@ DiscriminatedAnySafeValidatorModel = TypeAdapter(AnySafeValidatorModel) # type:
def raise_error_if_validation_fails(
- value: bool, validator: ValidatorDescription, message: Optional[str] = None, value_to_show: Optional[str] = None
+ value: bool, validator: ValidatorDescription, message: str | None = None, value_to_show: str | None = None
):
if not isinstance(value, bool):
raise AssertionError("Validator logic problem - computed validation value must be boolean")
diff --git a/lib/galaxy/tool_util_models/parameters.py b/lib/galaxy/tool_util_models/parameters.py
index c52cb34a818..d96f631357d 100644
--- a/lib/galaxy/tool_util_models/parameters.py
+++ b/lib/galaxy/tool_util_models/parameters.py
@@ -1,21 +1,23 @@
# attempt to model requires_value...
# conditional can descend...
+import builtins
from abc import abstractmethod
-from functools import lru_cache
-from typing import (
- Any,
+from collections.abc import (
Callable,
- cast,
- Dict,
- get_args,
Iterable,
Iterator,
- List,
Mapping,
- NamedTuple,
- Optional,
Sequence,
- Type,
+)
+from functools import lru_cache
+from typing import (
+ Annotated,
+ Any,
+ cast,
+ get_args,
+ Literal,
+ NamedTuple,
+ TypeAlias,
TypeVar,
Union,
)
@@ -44,14 +46,11 @@ from pydantic import (
from pydantic.json_schema import SkipJsonSchema
from pydantic_extra_types.color import Color
from typing_extensions import (
- Annotated,
- Literal,
Protocol,
)
from ._base import ToolSourceBaseModel
from ._types import (
- cast_as_type,
dict_type,
expand_annotation,
is_optional,
@@ -101,11 +100,11 @@ StateRepresentationT = Literal[
]
DEFAULT_MODEL_NAME = "DynamicModelForTool"
-RawStateDict = Dict[str, Any]
+RawStateDict = dict[str, Any]
# could be made more specific - validators need to be classmethod
-ValidatorDictT = Dict[str, Callable]
+ValidatorDictT = dict[str, Callable]
class DynamicModelInformation(NamedTuple):
@@ -122,21 +121,21 @@ class ConnectedValue(BaseModel):
discriminator: Literal["ConnectedValue"] = Field(alias="__class__")
-def allow_connected_value(type: Type):
- return union_type([type, ConnectedValue])
+def allow_connected_value(type_: type) -> type:
+ return union_type([type_, ConnectedValue])
-def allow_batching(job_template: DynamicModelInformation, batch_type: Optional[Type] = None) -> DynamicModelInformation:
- job_py_type: Type = job_template.definition[0]
+def allow_batching(job_template: DynamicModelInformation, batch_type: type | None = None) -> DynamicModelInformation:
+ job_py_type = job_template.definition[0]
default_value = job_template.definition[1]
batch_type = batch_type or job_py_type
class BatchRequest(StrictModel):
meta_class: Literal["Batch"] = Field(..., alias="__class__")
- values: List[batch_type] # type: ignore[valid-type]
- linked: Optional[bool] = None # maybe True instead?
+ values: list[batch_type] # type: ignore[valid-type]
+ linked: bool | None = None # maybe True instead?
- request_type = union_type([job_py_type, BatchRequest])
+ request_type = job_py_type | BatchRequest
return DynamicModelInformation(
job_template.name,
@@ -161,7 +160,7 @@ class ParamModel(Protocol):
# input value MUST be specified.
...
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
"""Return kwargs for pydantic Field() including json_schema_extra metadata."""
...
@@ -172,7 +171,7 @@ def safe_field_name(name: str) -> str:
return name
-def _label_value_dicts(options: List[Any]) -> List[Dict[str, Any]]:
+def _label_value_dicts(options: list[Any]) -> list[dict[str, Any]]:
return [{"label": o.label, "value": o.value, "selected": o.selected} for o in options]
@@ -181,10 +180,10 @@ _UNSET: Any = object()
def dynamic_model_information_from_py_type(
param_model: ParamModel,
- py_type: Type,
- requires_value: Optional[bool] = None,
- validators: Optional[Dict[str, Any]] = None,
- extra_json_schema: Optional[Dict[str, Any]] = None,
+ py_type: type,
+ requires_value: bool | None = None,
+ validators: dict[str, Any] | None = None,
+ extra_json_schema: dict[str, Any] | None = None,
default: Any = _UNSET,
) -> DynamicModelInformation:
name = safe_field_name(param_model.name)
@@ -224,7 +223,7 @@ class BaseToolParameterModelDefinition(ToolSourceBaseModel):
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
"""Return info needed to build Pydantic model at runtime for validation."""
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
"""Return kwargs for pydantic Field() including json_schema_extra metadata."""
return {"json_schema_extra": {"gx_type": self.parameter_type}}
@@ -232,16 +231,16 @@ class BaseToolParameterModelDefinition(ToolSourceBaseModel):
class BaseGalaxyToolParameterModelDefinition(BaseToolParameterModelDefinition):
hidden: bool = False
label: Annotated[
- Optional[str], Field(description="Will be displayed on the tool page as the label of the parameter.")
+ str | None, Field(description="Will be displayed on the tool page as the label of the parameter.")
] = None
help: Annotated[
- Optional[str],
+ str | None,
Field(
description="Short bit of text, rendered on the tool form just below the associated field to provide information about the field."
),
] = None
argument: Annotated[
- Optional[str],
+ str | None,
Field(
description="""If the parameter reflects just one command line argument of a certain tool, this tag should be set to that particular argument. It is rendered in parenthesis after the help section, and it will create the name attribute (if not given explicitly) from the argument attribute by stripping leading dashes and replacing all remaining dashes by underscores (e.g. if argument="--long-parameter" then name="long_parameter" is implicit)."""
),
@@ -249,8 +248,8 @@ class BaseGalaxyToolParameterModelDefinition(BaseToolParameterModelDefinition):
is_dynamic: bool = False
optional: Annotated[bool, Field(description="If `false`, parameter must have a value.")] = False
- def field_kwargs(self) -> Dict[str, Any]:
- kwargs: Dict[str, Any] = {}
+ def field_kwargs(self) -> dict[str, Any]:
+ kwargs: dict[str, Any] = {}
if self.label:
kwargs["title"] = self.label
description_parts = []
@@ -270,12 +269,12 @@ class LabelValue(BaseModel):
selected: bool
-TextCompatiableValidators = Union[
- LengthParameterValidatorModel,
- RegexParameterValidatorModel,
- ExpressionParameterValidatorModel,
- EmptyFieldParameterValidatorModel,
-]
+TextCompatiableValidators: TypeAlias = (
+ LengthParameterValidatorModel
+ | RegexParameterValidatorModel
+ | ExpressionParameterValidatorModel
+ | EmptyFieldParameterValidatorModel
+)
def pydantic_to_galaxy_type(value: Any) -> Any:
@@ -289,7 +288,7 @@ def pydantic_to_galaxy_type(value: Any) -> Any:
VT = TypeVar("VT", bound=StaticValidatorModel)
-def _json_schema_annotations_for(static_validator_models: Sequence[VT]) -> List[Any]:
+def _json_schema_annotations_for(static_validator_models: Sequence[VT]) -> list[Any]:
"""Extract JSON Schema-representable constraint annotations from validators.
Non-negated in_range and length validators have direct annotated_types
@@ -297,7 +296,7 @@ def _json_schema_annotations_for(static_validator_models: Sequence[VT]) -> List[
separately via json_schema_extra since StringConstraints is incompatible
with non-string types (e.g. AnyUrl).
"""
- annotations: List[Any] = []
+ annotations: list[Any] = []
for v in static_validator_models:
if isinstance(v, InRangeParameterValidatorModel) and not v.negate:
if v.min is not None:
@@ -312,7 +311,7 @@ def _json_schema_annotations_for(static_validator_models: Sequence[VT]) -> List[
return annotations
-def _json_schema_extra_for_validators(validators: Sequence[VT]) -> Dict[str, Any]:
+def _json_schema_extra_for_validators(validators: Sequence[VT]) -> dict[str, Any]:
"""Extract JSON Schema keywords for validators best handled via json_schema_extra.
Regex pattern is emitted here rather than as a type annotation because
@@ -320,7 +319,7 @@ def _json_schema_extra_for_validators(validators: Sequence[VT]) -> Dict[str, Any
Negated length uses ``not: {minLength, maxLength}`` since the non-negated
form is handled by annotated_types.
"""
- extra: Dict[str, Any] = {}
+ extra: dict[str, Any] = {}
for v in validators:
if isinstance(v, RegexParameterValidatorModel) and not v.negate:
pattern = v.expression
@@ -331,7 +330,7 @@ def _json_schema_extra_for_validators(validators: Sequence[VT]) -> Dict[str, Any
break
for v in validators:
if isinstance(v, LengthParameterValidatorModel) and v.negate:
- not_constraint: Dict[str, Any] = {}
+ not_constraint: dict[str, Any] = {}
if v.min is not None:
not_constraint["minLength"] = v.min
if v.max is not None:
@@ -343,8 +342,8 @@ def _json_schema_extra_for_validators(validators: Sequence[VT]) -> Dict[str, Any
def decorate_type_with_validators_if_needed(
- py_type: Type, static_validator_models: Sequence[VT], optional: bool = False
-) -> Type:
+ py_type: type, static_validator_models: Sequence[VT], optional: bool = False
+) -> type:
pydantic_validator = pydantic_validator_for(static_validator_models, optional=optional)
json_schema_annotations = _json_schema_annotations_for(static_validator_models)
all_annotations = json_schema_annotations[:]
@@ -357,7 +356,7 @@ def decorate_type_with_validators_if_needed(
# Looks like Annotated only work with one PlainValidator so condensing all static validators
# into a single PlainValidator for pydantic.
-def pydantic_validator_for(static_validator_models: Sequence[VT], optional: bool = False) -> Optional[AfterValidator]:
+def pydantic_validator_for(static_validator_models: Sequence[VT], optional: bool = False) -> AfterValidator | None:
if static_validator_models:
@@ -380,11 +379,11 @@ class TextParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_text"] = "gx_text"
type: Literal["text"]
area: bool = False
- default_value: Optional[str] = Field(default=None, alias="value")
- default_options: List[LabelValue] = []
- validators: List[TextCompatiableValidators] = []
+ default_value: str | None = Field(default=None, alias="value")
+ default_options: list[LabelValue] = []
+ validators: list[TextCompatiableValidators] = []
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
extra = kwargs["json_schema_extra"]
extra["gx_area"] = self.area
@@ -393,11 +392,11 @@ class TextParameterModel(BaseGalaxyToolParameterModelDefinition):
return kwargs
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return optional_if_needed(StrictStr, self.optional)
@property
- def py_type_relaxed_request(self) -> Type:
+ def py_type_relaxed_request(self) -> builtins.type:
# such a hack but explicit nulls are always allowed in the API even for non-optional
# parameters - it becomes "" in the internal state.
return optional(StrictStr)
@@ -424,19 +423,19 @@ class TextParameterModel(BaseGalaxyToolParameterModelDefinition):
return False
-NumberCompatiableValidators = Union[InRangeParameterValidatorModel,]
+NumberCompatiableValidators: TypeAlias = InRangeParameterValidatorModel
class IntegerParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_integer"] = "gx_integer"
type: Literal["integer"]
optional: bool = False
- value: Optional[int] = None
- min: Optional[int] = None
- max: Optional[int] = None
- validators: List[NumberCompatiableValidators] = []
+ value: int | None = None
+ min: int | None = None
+ max: int | None = None
+ validators: list[NumberCompatiableValidators] = []
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
extra = kwargs["json_schema_extra"]
if self.min is not None:
@@ -446,7 +445,7 @@ class IntegerParameterModel(BaseGalaxyToolParameterModelDefinition):
return kwargs
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return optional_if_needed(StrictInt, self.optional)
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -492,17 +491,17 @@ def _convert_infinity_sentinel(v: Any) -> Any:
class FloatParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_float"] = "gx_float"
type: Literal["float"]
- value: Optional[float] = None
- min: Optional[float] = None
- max: Optional[float] = None
- validators: List[NumberCompatiableValidators] = []
+ value: float | None = None
+ min: float | None = None
+ max: float | None = None
+ validators: list[NumberCompatiableValidators] = []
@field_validator("value", "min", "max", mode="before")
@classmethod
def convert_infinity_sentinels(cls, v: Any) -> Any:
return _convert_infinity_sentinel(v)
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
extra = kwargs["json_schema_extra"]
if self.min is not None:
@@ -512,7 +511,7 @@ class FloatParameterModel(BaseGalaxyToolParameterModelDefinition):
return kwargs
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return optional_if_needed(union_type([StrictInt, StrictFloat]), self.optional)
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -531,7 +530,7 @@ class FloatParameterModel(BaseGalaxyToolParameterModelDefinition):
# Convert Galaxy JSON sentinel strings ("__Infinity__", "__-Infinity__") to Python floats
# before Pydantic validates the field. These sentinels appear when float('inf') values are
# round-tripped through Galaxy's safe_dumps/json.loads path (e.g. GET /api/tools/{id}/test_data).
- dynamic_validators: Dict[str, Any] = {
+ dynamic_validators: dict[str, Any] = {
"infinity_sentinel": field_validator(safe_field_name(self.name), mode="before")(_convert_infinity_sentinel)
}
return dynamic_model_information_from_py_type(
@@ -554,10 +553,10 @@ CollectionInternalSrcT = Literal["hdca", "dce"]
class LegacyRequestModelAttributes(StrictModel):
# Here for bioblend's sake, should be stripped
- map_over_type: SkipJsonSchema[Optional[str]] = Field(None, exclude=True)
- hid: SkipJsonSchema[Optional[int]] = Field(None, exclude=True)
- workflow_step_id: SkipJsonSchema[Optional[str]] = Field(None, exclude=True)
- label: SkipJsonSchema[Optional[str]] = Field(None, exclude=True)
+ map_over_type: SkipJsonSchema[str | None] = Field(None, exclude=True)
+ hid: SkipJsonSchema[int | None] = Field(None, exclude=True)
+ workflow_step_id: SkipJsonSchema[str | None] = Field(None, exclude=True)
+ label: SkipJsonSchema[str | None] = Field(None, exclude=True)
class DataRequestHda(LegacyRequestModelAttributes):
@@ -592,14 +591,14 @@ class FileHash(StrictModel):
class BaseDataRequest(StrictModel):
url: StrictStr = Field(..., alias="location", validation_alias=AliasChoices("url", "location"))
- name: Optional[StrictStr] = None
+ name: StrictStr | None = None
ext: StrictStr
dbkey: StrictStr = "?"
deferred: StrictBool = False
- created_from_basename: Optional[StrictStr] = None
- info: Optional[StrictStr] = None
- tags: Optional[List[str]] = None
- hashes: Optional[List[FileHash]] = None
+ created_from_basename: StrictStr | None = None
+ info: StrictStr | None = None
+ tags: list[str] | None = None
+ hashes: list[FileHash] | None = None
space_to_tab: bool = False
to_posix_lines: bool = False
@@ -651,7 +650,7 @@ class CollectionElementCollectionRequestUri(StrictModel):
validation_alias=AliasChoices("identifier", "name"),
)
collection_type: StrictStr
- elements: List["CollectionRequestUriElement"]
+ elements: list["CollectionRequestUriElement"]
@model_validator(mode="before")
@classmethod
@@ -665,7 +664,7 @@ class CollectionElementCollectionRequestUri(StrictModel):
return data
-def _collection_element_discriminator(value: Any) -> Optional[str]:
+def _collection_element_discriminator(value: Any) -> str | None:
if isinstance(value, dict):
return value.get("class") or value.get("class_")
return getattr(value, "class_", None)
@@ -675,10 +674,8 @@ def _collection_element_discriminator(value: Any) -> Optional[str]:
# the recursive Field(discriminator="class_") on this self-referential union;
# json_schema_extra restores the OpenAPI discriminator metadata.
CollectionRequestUriElement = Annotated[
- Union[
- Annotated[CollectionElementCollectionRequestUri, Tag("Collection")],
- Annotated[CollectionElementDataRequestUri, Tag("File")],
- ],
+ Annotated[CollectionElementCollectionRequestUri, Tag("Collection")]
+ | Annotated[CollectionElementDataRequestUri, Tag("File")],
Discriminator(_collection_element_discriminator),
Field(
json_schema_extra={
@@ -697,22 +694,22 @@ CollectionRequestUriElement = Annotated[
class DataRequestCollectionUri(StrictModel):
class_: Literal["Collection"] = Field(..., alias="class")
collection_type: str
- elements: List[CollectionRequestUriElement]
+ elements: list[CollectionRequestUriElement]
deferred: StrictBool = False
- name: Optional[StrictStr] = None
+ name: StrictStr | None = None
src: None = Field(None, exclude=True)
# Sample sheet metadata
- column_definitions: Optional[SampleSheetColumnDefinitions] = None
- rows: Optional[Dict[str, SampleSheetRow]] = None
+ column_definitions: SampleSheetColumnDefinitions | None = None
+ rows: dict[str, SampleSheetRow] | None = None
_DataRequest = Annotated[
- Union[DataRequestHda, DataRequestLdda, DataRequestLd, DataRequestDce, DataRequestUri], Field(discriminator="src")
+ DataRequestHda | DataRequestLdda | DataRequestLd | DataRequestDce | DataRequestUri, Field(discriminator="src")
]
-DataRequest: Type = cast(Type, _DataRequest)
+DataRequest: type = cast(type, _DataRequest)
-DataOrCollectionRequest = Union[_DataRequest, FileRequestUri, DataRequestCollectionUri, DataRequestHdca]
-FileOrCollectionRequest = Annotated[Union[FileRequestUri, DataRequestCollectionUri], Field(discriminator="class_")]
+DataOrCollectionRequest = _DataRequest | FileRequestUri | DataRequestCollectionUri | DataRequestHdca
+FileOrCollectionRequest = Annotated[FileRequestUri | DataRequestCollectionUri, Field(discriminator="class_")]
DataRequestHda.model_rebuild()
DataRequestLd.model_rebuild()
@@ -729,13 +726,13 @@ DataOrCollectionRequestAdapter: TypeAdapter[DataOrCollectionRequest] = TypeAdapt
class BatchDataHdcaInstance(StrictModel):
src: Literal["hdca"]
id: StrictStr
- map_over_type: Optional[str] = None
+ map_over_type: str | None = None
class BatchDataDceInstance(StrictModel):
src: Literal["dce"]
id: StrictStr
- map_over_type: Optional[str] = None
+ map_over_type: str | None = None
class BatchDataNonCollectionInstance(StrictModel):
@@ -743,10 +740,10 @@ class BatchDataNonCollectionInstance(StrictModel):
id: StrictStr
-BatchDataInstance: Type = cast(
- Type,
+BatchDataInstance: type = cast(
+ type,
Annotated[
- Union[BatchDataHdcaInstance, BatchDataDceInstance, BatchDataNonCollectionInstance], Field(discriminator="src")
+ BatchDataHdcaInstance | BatchDataDceInstance | BatchDataNonCollectionInstance, Field(discriminator="src")
],
)
@@ -770,28 +767,24 @@ def multi_data_discriminator(v: Any) -> str:
return ""
-def tag(field: Type, tag: str) -> Type:
+def tag(field: type, tag: str) -> type:
return Annotated[field, Tag(tag)] # type: ignore[return-value]
MultiDataInstanceDiscriminator = Discriminator(multi_data_discriminator)
-MultiDataInstance: Type = cast(
- Type,
+MultiDataInstance = cast(
+ type,
Annotated[
- union_type(
- [
- tag(DataRequestHda, "data_request_hda"),
- tag(DataRequestLdda, "data_request_ldda"),
- tag(DataRequestHdca, "data_request_hdca"),
- tag(DataRequestDce, "data_request_dce"),
- tag(DataRequestUri, "data_request_uri"),
- tag(DataRequestCollectionUri, "data_request_collection_uri"),
- ]
- ),
+ tag(DataRequestHda, "data_request_hda")
+ | tag(DataRequestLdda, "data_request_ldda")
+ | tag(DataRequestHdca, "data_request_hdca")
+ | tag(DataRequestDce, "data_request_dce")
+ | tag(DataRequestUri, "data_request_uri")
+ | tag(DataRequestCollectionUri, "data_request_collection_uri"),
Field(discriminator=MultiDataInstanceDiscriminator),
],
)
-MultiDataRequest: Type = union_type([MultiDataInstance, list_type(MultiDataInstance)])
+MultiDataRequest = union_type([MultiDataInstance, list_type(MultiDataInstance)])
class DataRequestInternalHda(StrictModel):
@@ -824,25 +817,23 @@ class DataInternalJson(StrictModel):
]
location: str
path: Annotated[str, Field(description="The absolute path to the file on disk.")]
- listing: Optional[List[str]] = None # Should be recursive
- nameroot: Annotated[Optional[str], Field(description="The basename root such that nameroot + nameext == basename")]
- nameext: Annotated[
- Optional[str], Field(description="The basename extension such that nameroot + nameext == basename")
- ]
+ listing: list[str] | None = None # Should be recursive
+ nameroot: Annotated[str | None, Field(description="The basename root such that nameroot + nameext == basename")]
+ nameext: Annotated[str | None, Field(description="The basename extension such that nameroot + nameext == basename")]
format: Annotated[str, Field(description="The datatype extension of the file, e.g. 'txt', 'bam', 'fastq.gz'.")]
# "secondaryFiles": List[Any],
- checksum: Optional[str] = None
+ checksum: str | None = None
size: int
# When a gx_data param receives a DCE (subcollection mapping), preserve element_identifier
# for output naming and collection traceability
- element_identifier: Optional[str] = None
+ element_identifier: str | None = None
class DataCollectionElementInternalJson(DataInternalJson):
"""A file within a collection element - adds collection-specific metadata."""
element_identifier: str
- columns: Optional[List[Any]] = None # for sample_sheet elements
+ columns: list[Any] | None = None # for sample_sheet elements
# Collection runtime models with metadata
@@ -850,14 +841,15 @@ class DataCollectionInternalJsonBase(StrictModel):
"""Base model for collection runtime representations with metadata."""
class_: Annotated[Literal["Collection"], Field(alias="class")]
- name: Optional[str] # None for raw DatasetCollection inputs
+ name: str | None # None for raw DatasetCollection inputs
collection_type: str
- tags: List[str] = []
+ elements: Any
+ tags: list[str] = []
# Special metadata fields (optional, type-dependent)
- column_definitions: Optional[List[Dict[str, Any]]] = None # for sample_sheet
- fields: Optional[List[Dict[str, Any]]] = None # for record
- has_single_item: Optional[bool] = None # for paired_or_unpaired
- columns: Optional[List[Any]] = None # for sample_sheet elements
+ column_definitions: list[dict[str, Any]] | None = None # for sample_sheet
+ fields: list[dict[str, Any]] | None = None # for record
+ has_single_item: bool | None = None # for paired_or_unpaired
+ columns: list[Any] | None = None # for sample_sheet elements
model_config = ConfigDict(populate_by_name=True)
@@ -878,21 +870,21 @@ class DataCollectionListRuntime(DataCollectionInternalJsonBase):
"""List collection runtime representation."""
collection_type: Literal["list"]
- elements: List[DataCollectionElementInternalJson]
+ elements: list[DataCollectionElementInternalJson]
class DataCollectionSampleSheetRuntime(DataCollectionInternalJsonBase):
"""Sample sheet collection runtime representation."""
collection_type: Literal["sample_sheet"]
- elements: List[DataCollectionElementInternalJson]
+ elements: list[DataCollectionElementInternalJson]
class DataCollectionRecordRuntime(DataCollectionInternalJsonBase):
"""Record collection runtime representation."""
collection_type: Literal["record"]
- elements: Dict[
+ elements: dict[
str,
Union[
DataCollectionElementInternalJson, "DataCollectionNestedListRuntime", "DataCollectionNestedRecordRuntime"
@@ -904,14 +896,12 @@ class DataCollectionPairedOrUnpairedRuntime(DataCollectionInternalJsonBase):
"""Paired or Unpaired collection runtime representation."""
collection_type: Literal["paired_or_unpaired"]
- elements: Dict[str, DataCollectionElementInternalJson]
+ elements: dict[str, DataCollectionElementInternalJson]
class DataCollectionNestedListRuntime(DataCollectionInternalJsonBase):
"""Nested collection with list-like outer structure (list:*, sample_sheet:*)."""
- collection_type: str
-
@field_validator("collection_type")
@classmethod
def must_be_nested_list_like(cls, v: str) -> str:
@@ -922,7 +912,7 @@ class DataCollectionNestedListRuntime(DataCollectionInternalJsonBase):
raise ValueError(f'Outer type must be list-like (list, sample_sheet), got "{first_segment}"')
return v
- elements: List[
+ elements: list[
Union[
"DataCollectionListRuntime",
"DataCollectionSampleSheetRuntime",
@@ -938,8 +928,6 @@ class DataCollectionNestedListRuntime(DataCollectionInternalJsonBase):
class DataCollectionNestedRecordRuntime(DataCollectionInternalJsonBase):
"""Nested collection with record-like outer structure (paired:*, record:*)."""
- collection_type: str
-
@field_validator("collection_type")
@classmethod
def must_be_nested_record_like(cls, v: str) -> str:
@@ -950,7 +938,7 @@ class DataCollectionNestedRecordRuntime(DataCollectionInternalJsonBase):
raise ValueError(f'Outer type must be record-like, got list-like "{first_segment}"')
return v
- elements: Dict[
+ elements: dict[
str,
Union[
DataCollectionElementInternalJson,
@@ -969,7 +957,7 @@ DataCollectionNestedListRuntime.model_rebuild()
DataCollectionNestedRecordRuntime.model_rebuild()
-_LEAF_COLLECTION_MODELS: Dict[str, Type] = {
+_LEAF_COLLECTION_MODELS: dict[str, type[Any]] = {
"list": DataCollectionListRuntime,
"paired": DataCollectionPairedRuntime,
"record": DataCollectionRecordRuntime,
@@ -979,7 +967,7 @@ _LEAF_COLLECTION_MODELS: Dict[str, Type] = {
@lru_cache(maxsize=128)
-def build_collection_model_for_type(collection_type: str) -> Optional[Type]:
+def build_collection_model_for_type(collection_type: str) -> type[DataCollectionInternalJsonBase] | None:
"""Dynamically generate a Pydantic model for a specific collection_type.
Simple types -> existing static model.
@@ -1066,36 +1054,30 @@ def collection_runtime_discriminator(v: Any) -> str:
raise ValueError(f"Unknown collection_type for runtime discrimination: '{ct}'")
-CollectionRuntimeDiscriminated: Type = cast(
- Type,
+CollectionRuntimeDiscriminated: type = cast(
+ type,
Annotated[
- Union[
- Annotated[DataCollectionListRuntime, Tag("list")],
- Annotated[DataCollectionSampleSheetRuntime, Tag("sample_sheet")],
- Annotated[DataCollectionPairedRuntime, Tag("paired")],
- Annotated[DataCollectionRecordRuntime, Tag("record")],
- Annotated[DataCollectionPairedOrUnpairedRuntime, Tag("paired_or_unpaired")],
- Annotated[DataCollectionNestedListRuntime, Tag("nested_list")],
- Annotated[DataCollectionNestedRecordRuntime, Tag("nested_record")],
- ],
+ Annotated[DataCollectionListRuntime, Tag("list")]
+ | Annotated[DataCollectionSampleSheetRuntime, Tag("sample_sheet")]
+ | Annotated[DataCollectionPairedRuntime, Tag("paired")]
+ | Annotated[DataCollectionRecordRuntime, Tag("record")]
+ | Annotated[DataCollectionPairedOrUnpairedRuntime, Tag("paired_or_unpaired")]
+ | Annotated[DataCollectionNestedListRuntime, Tag("nested_list")]
+ | Annotated[DataCollectionNestedRecordRuntime, Tag("nested_record")],
Discriminator(collection_runtime_discriminator),
],
)
-DataRequestInternal: Type = cast(
- Type,
+DataRequestInternal = cast(
+ type,
Annotated[
- union_type(
- [
- tag(DataRequestInternalHda, "data_request_hda"),
- tag(DataRequestInternalLdda, "data_request_ldda"),
- tag(DataRequestInternalHdca, "data_request_hdca"),
- tag(DataRequestInternalDce, "data_request_dce"),
- tag(DataRequestUri, "data_request_uri"),
- tag(DataRequestCollectionUri, "data_request_collection_uri"),
- ]
- ),
+ tag(DataRequestInternalHda, "data_request_hda")
+ | tag(DataRequestInternalLdda, "data_request_ldda")
+ | tag(DataRequestInternalHdca, "data_request_hdca")
+ | tag(DataRequestInternalDce, "data_request_dce")
+ | tag(DataRequestUri, "data_request_uri")
+ | tag(DataRequestCollectionUri, "data_request_collection_uri"),
Field(discriminator=MultiDataInstanceDiscriminator),
],
)
@@ -1104,20 +1086,18 @@ DataRequestInternal: Type = cast(
class DatasetCollectionElementReference(StrictModel):
src: Literal["dce"]
id: StrictInt
- map_over_type: Optional[str] = None
+ map_over_type: str | None = None
-DataRequestInternalDereferencedT = Union[
- DataRequestInternalHda, DataRequestInternalLdda, DatasetCollectionElementReference
-]
-DataRequestInternalDereferenced: Type = cast(
- Type,
+DataRequestInternalDereferencedT = DataRequestInternalHda | DataRequestInternalLdda | DatasetCollectionElementReference
+DataRequestInternalDereferenced: type = cast(
+ type,
Annotated[DataRequestInternalDereferencedT, Field(discriminator="src")],
)
-DataJobInternalT = Union[DataRequestInternalHda, DataRequestInternalLdda, DatasetCollectionElementReference]
-DataJobInternal: Type = cast(
- Type,
+DataJobInternalT = DataRequestInternalHda | DataRequestInternalLdda | DatasetCollectionElementReference
+DataJobInternal: type = cast(
+ type,
Annotated[DataJobInternalT, Field(discriminator="src")],
)
@@ -1125,13 +1105,13 @@ DataJobInternal: Type = cast(
class BatchDataHdcaInstanceInternal(StrictModel):
src: Literal["hdca"]
id: StrictInt
- map_over_type: Optional[str] = None
+ map_over_type: str | None = None
class BatchDataDceInstanceInternal(StrictModel):
src: Literal["dce"]
id: StrictInt
- map_over_type: Optional[str] = None
+ map_over_type: str | None = None
class BatchDataNonCollectionInstanceInternal(StrictModel):
@@ -1139,38 +1119,36 @@ class BatchDataNonCollectionInstanceInternal(StrictModel):
id: StrictInt
-BatchDataInstanceInternal: Type = cast(
- Type,
+BatchDataInstanceInternal: type = cast(
+ type,
Annotated[
- Union[BatchDataHdcaInstanceInternal, BatchDataDceInstanceInternal, BatchDataNonCollectionInstanceInternal],
+ BatchDataHdcaInstanceInternal | BatchDataDceInstanceInternal | BatchDataNonCollectionInstanceInternal,
Field(discriminator="src"),
],
)
-MultiDataInstanceInternal: Type = cast(
- Type,
+MultiDataInstanceInternal = cast(
+ type,
Annotated[
- Union[
- DataRequestInternalHda,
- DataRequestInternalLdda,
- DataRequestInternalHdca,
- DataRequestInternalDce,
- DataRequestUri,
- ],
+ DataRequestInternalHda
+ | DataRequestInternalLdda
+ | DataRequestInternalHdca
+ | DataRequestInternalDce
+ | DataRequestUri,
Field(discriminator="src"),
],
)
-MultiDataInstanceInternalDereferenced: Type = cast(
- Type,
+MultiDataInstanceInternalDereferenced: type = cast(
+ type,
Annotated[
- Union[DataRequestInternalHda, DataRequestInternalLdda, DataRequestInternalHdca, DataRequestInternalDce],
+ DataRequestInternalHda | DataRequestInternalLdda | DataRequestInternalHdca | DataRequestInternalDce,
Field(discriminator="src"),
],
)
-MultiDataRequestInternal: Type = union_type([MultiDataInstanceInternal, list_type(MultiDataInstanceInternal)])
-MultiDataRequestInternalDereferenced: Type = union_type(
+MultiDataRequestInternal = union_type([MultiDataInstanceInternal, list_type(MultiDataInstanceInternal)])
+MultiDataRequestInternalDereferenced = union_type(
[MultiDataInstanceInternalDereferenced, list_type(MultiDataInstanceInternalDereferenced)]
)
@@ -1181,7 +1159,7 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_data"] = "gx_data"
type: Literal["data"]
extensions: Annotated[
- List[str],
+ list[str],
Field(
validation_alias=AliasChoices("extensions", "format"),
description="Limit inputs to datasets with these extensions. Use 'data' to allow all input datasets.",
@@ -1189,9 +1167,9 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
),
] = ["data"]
multiple: Annotated[bool, Field(description="Allow multiple values to be selected.")] = False
- min: Optional[int] = None
- max: Optional[int] = None
- url_default: Optional[str] = None
+ min: int | None = None
+ max: int | None = None
+ url_default: str | None = None
@model_validator(mode="before")
@classmethod
@@ -1200,7 +1178,7 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
raise ValueError("Specify either 'extensions' or 'format', not both")
return data
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
extra = kwargs["json_schema_extra"]
extra["gx_extensions"] = self.extensions
@@ -1212,8 +1190,8 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
return kwargs
@property
- def py_type(self) -> Type:
- base_model: Type
+ def py_type(self) -> builtins.type:
+ base_model: type
if self.multiple:
base_model = MultiDataRequest
else:
@@ -1221,8 +1199,8 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
return optional_if_needed(base_model, self.optional)
@property
- def py_type_internal_json(self) -> Type:
- base_model: Type
+ def py_type_internal_json(self) -> builtins.type:
+ base_model: type
if self.multiple:
base_model = list_type(DataInternalJson)
else:
@@ -1230,8 +1208,8 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
return optional_if_needed(base_model, self.optional)
@property
- def py_type_internal(self) -> Type:
- base_model: Type
+ def py_type_internal(self) -> builtins.type:
+ base_model: type
if self.multiple:
base_model = MultiDataRequestInternal
else:
@@ -1239,8 +1217,8 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
return optional_if_needed(base_model, self.optional)
@property
- def py_type_internal_dereferenced(self) -> Type:
- base_model: Type
+ def py_type_internal_dereferenced(self) -> builtins.type:
+ base_model: type
if self.multiple:
base_model = MultiDataRequestInternalDereferenced
else:
@@ -1248,8 +1226,8 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
return optional_if_needed(base_model, self.optional)
@property
- def py_type_job_internal(self) -> Type:
- base_model: Type
+ def py_type_job_internal(self) -> builtins.type:
+ base_model: type
if self.multiple:
base_model = MultiDataRequestInternalDereferenced
else:
@@ -1257,8 +1235,8 @@ class DataParameterModel(BaseGalaxyToolParameterModelDefinition):
return optional_if_needed(base_model, self.optional)
@property
- def py_type_test_case(self) -> Type:
- base_model: Type
+ def py_type_test_case(self) -> builtins.type:
+ base_model: type
if self.multiple:
base_model = list_type(JsonTestDatasetDefDict)
else:
@@ -1326,16 +1304,16 @@ class DataCollectionRequest(StrictModel):
class BatchCollectionInstance(StrictModel):
src: CollectionSrcT
id: StrictStr
- map_over_type: Optional[str] = None
+ map_over_type: str | None = None
class BatchCollectionInstanceInternal(StrictModel):
src: CollectionInternalSrcT
id: StrictInt
- map_over_type: Optional[str] = None
+ map_over_type: str | None = None
-DataCollectionRequestOrCollectionUri: Type = union_type([DataCollectionRequest, DataRequestCollectionUri])
+DataCollectionRequestOrCollectionUri: type = union_type([DataCollectionRequest, DataRequestCollectionUri])
class DataCollectionRequestInternal(StrictModel):
@@ -1350,7 +1328,7 @@ class DataCollectionRequestInternal(StrictModel):
id: StrictInt
-DataCollectionRequestInternalOrCollectionUri: Type = union_type(
+DataCollectionRequestInternalOrCollectionUri: type = union_type(
[DataCollectionRequestInternal, DataRequestCollectionUri]
)
CollectionAdapterSrcT = Literal["CollectionAdapter"]
@@ -1375,13 +1353,11 @@ class AdaptedDataCollectionPromoteDatasetsToCollectionRequest(AdaptedDataCollect
adapter_type: Literal["PromoteDatasetsToCollection"]
# could allow list in here without changing much else I think but I'm trying to keep these tight in scope
collection_type: Literal["paired", "paired_or_unpaired"]
- adapting: List[AdapterElementRequest]
+ adapting: list[AdapterElementRequest]
AdaptedDataCollectionRequest = Annotated[
- Union[
- AdaptedDataCollectionPromoteDatasetToCollectionRequest, AdaptedDataCollectionPromoteDatasetsToCollectionRequest
- ],
+ AdaptedDataCollectionPromoteDatasetToCollectionRequest | AdaptedDataCollectionPromoteDatasetsToCollectionRequest,
Field(discriminator="adapter_type"),
]
AdaptedDataCollectionRequestTypeAdapter = TypeAdapter(AdaptedDataCollectionRequest) # type: ignore[var-annotated]
@@ -1406,22 +1382,18 @@ class AdaptedDataCollectionPromoteDatasetsToCollectionRequestInternal(AdaptedDat
adapter_type: Literal["PromoteDatasetsToCollection"]
# could allow list in here without changing much else I think but I'm trying to keep these tight in scope
collection_type: Literal["paired", "paired_or_unpaired"]
- adapting: List[AdapterElementRequestInternal]
+ adapting: list[AdapterElementRequestInternal]
AdaptedDataCollectionRequestInternal = Annotated[
- Union[
- AdaptedDataCollectionPromoteCollectionElementToCollectionRequestInternal,
- AdaptedDataCollectionPromoteDatasetToCollectionRequestInternal,
- AdaptedDataCollectionPromoteDatasetsToCollectionRequestInternal,
- ],
+ AdaptedDataCollectionPromoteCollectionElementToCollectionRequestInternal
+ | AdaptedDataCollectionPromoteDatasetToCollectionRequestInternal
+ | AdaptedDataCollectionPromoteDatasetsToCollectionRequestInternal,
Field(discriminator="adapter_type"),
]
-AdaptedDataCollectionRequestInternalTypeAdapter = TypeAdapter(
- AdaptedDataCollectionRequestInternal
-) # type: ignore[var-annotated]
+AdaptedDataCollectionRequestInternalTypeAdapter = TypeAdapter(AdaptedDataCollectionRequestInternal) # type: ignore[var-annotated]
-DataCollectionJobInternal: Type = Union[DataCollectionRequestInternal, AdaptedDataCollectionRequestInternal] # type: ignore[assignment]
+DataCollectionJobInternal = cast(type, DataCollectionRequestInternal | AdaptedDataCollectionRequestInternal)
class DataCollectionParameterModel(BaseGalaxyToolParameterModelDefinition):
@@ -1429,12 +1401,12 @@ class DataCollectionParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_data_collection"] = "gx_data_collection"
type: Literal["data_collection"]
- collection_type: Optional[str] = None
+ collection_type: str | None = None
extensions: Annotated[
- List[str],
+ list[str],
Field(validation_alias=AliasChoices("extensions", "format")),
] = ["data"]
- value: Optional[Dict[str, Any]]
+ value: dict[str, Any] | None
@model_validator(mode="before")
@classmethod
@@ -1443,21 +1415,21 @@ class DataCollectionParameterModel(BaseGalaxyToolParameterModelDefinition):
raise ValueError("Specify either 'extensions' or 'format', not both")
return data
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
kwargs["json_schema_extra"]["gx_extensions"] = self.extensions
return kwargs
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return optional_if_needed(DataCollectionRequestOrCollectionUri, self.optional)
@property
- def py_type_internal(self) -> Type:
+ def py_type_internal(self) -> builtins.type:
return optional_if_needed(DataCollectionRequestInternalOrCollectionUri, self.optional)
@property
- def py_type_internal_dereferenced(self) -> Type:
+ def py_type_internal_dereferenced(self) -> builtins.type:
return optional_if_needed(DataCollectionRequestInternal, self.optional)
def _runtime_model_for_collection_type(self, ct: str) -> tuple:
@@ -1467,13 +1439,12 @@ class DataCollectionParameterModel(BaseGalaxyToolParameterModelDefinition):
Uses build_collection_model_for_type which handles both leaf and nested types
via _LEAF_COLLECTION_MODELS lookup + recursive dynamic model generation.
"""
- model = build_collection_model_for_type(ct)
- if model is not None:
+ if (model := build_collection_model_for_type(ct)) is not None:
return (model, ct)
return (None, None)
@property
- def py_type_internal_json(self) -> Type:
+ def py_type_internal_json(self) -> builtins.type:
# Return normalized collection runtime models with metadata
if not self.collection_type:
# Unknown collection_type - use full discriminated union
@@ -1482,26 +1453,25 @@ class DataCollectionParameterModel(BaseGalaxyToolParameterModelDefinition):
# Handle comma-separated collection types (e.g., "list,paired")
if "," in self.collection_type:
types = [t.strip() for t in self.collection_type.split(",")]
- tagged_types = []
+ tagged_types: list[type] = []
tags_seen: set = set()
for t in types:
model, tag_str = self._runtime_model_for_collection_type(t)
if model and tag_str not in tags_seen:
tags_seen.add(tag_str)
- tagged_types.append(Annotated[model, Tag(tag_str)])
+ tagged_types.append(cast(type, Annotated[model, Tag(tag_str)]))
if tagged_types:
if len(tagged_types) == 1:
# Single type - no union needed, unwrap Annotated to get base model
- base_type: Type = get_args(tagged_types[0])[0]
+ base_type: type = get_args(tagged_types[0])[0]
else:
# Multiple types - build discriminated union
# Use _collection_type_discriminator which returns full collection_type,
# matching both simple tags ("list") and dynamic tags ("list:paired")
- base_type = cast(
- Type, Annotated[Union[tuple(tagged_types)], Discriminator(_collection_type_discriminator)]
- )
+ tagged_union = union_type(tagged_types)
+ base_type = cast(type, Annotated[tagged_union, Discriminator(_collection_type_discriminator)])
return optional_if_needed(base_type, self.optional)
# Fall through to full union if no models matched
@@ -1562,11 +1532,11 @@ class DataCollectionParameterModel(BaseGalaxyToolParameterModelDefinition):
class HiddenParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_hidden"] = "gx_hidden"
type: Literal["hidden"]
- value: Optional[str]
- validators: List[TextCompatiableValidators] = []
+ value: str | None
+ validators: list[TextCompatiableValidators] = []
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return optional_if_needed(StrictStr, self.optional)
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -1588,7 +1558,7 @@ class HiddenParameterModel(BaseGalaxyToolParameterModelDefinition):
return not self.optional and self.value is None
-def ensure_color_valid(value: Optional[Any]):
+def ensure_color_valid(value: Any | None):
if value is None:
return
if not isinstance(value, str):
@@ -1602,15 +1572,15 @@ def ensure_color_valid(value: Optional[Any]):
class ColorParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_color"] = "gx_color"
type: Literal["color"]
- value: Optional[str] = None
+ value: str | None = None
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
kwargs["json_schema_extra"]["format"] = "color"
return kwargs
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return optional_if_needed(StrictStr, self.optional)
@staticmethod
@@ -1658,12 +1628,12 @@ class ColorParameterModel(BaseGalaxyToolParameterModelDefinition):
class BooleanParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_boolean"] = "gx_boolean"
type: Literal["boolean"]
- value: Optional[bool] = False
- truevalue: Optional[str] = None
- falsevalue: Optional[str] = None
+ value: bool | None = False
+ truevalue: str | None = None
+ falsevalue: str | None = None
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return optional_if_needed(StrictBool, self.optional)
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -1685,10 +1655,10 @@ class BooleanParameterModel(BaseGalaxyToolParameterModelDefinition):
class DirectoryUriParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_directory_uri"] = "gx_directory_uri"
type: Literal["directory"]
- validators: List[TextCompatiableValidators] = []
+ validators: list[TextCompatiableValidators] = []
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return AnyUrl
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -1713,12 +1683,12 @@ class DirectoryUriParameterModel(BaseGalaxyToolParameterModelDefinition):
class RulesMapping(StrictModel):
type: str
- columns: List[StrictInt]
+ columns: list[StrictInt]
class RulesModel(StrictModel):
- rules: List[Dict[str, Any]]
- mapping: List[RulesMapping]
+ rules: list[dict[str, Any]]
+ mapping: list[RulesMapping]
class RulesParameterModel(BaseGalaxyToolParameterModelDefinition):
@@ -1726,7 +1696,7 @@ class RulesParameterModel(BaseGalaxyToolParameterModelDefinition):
type: Literal["rules"]
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return RulesModel
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -1737,17 +1707,17 @@ class RulesParameterModel(BaseGalaxyToolParameterModelDefinition):
return True
-SelectCompatiableValidators = Union[NoOptionsParameterValidatorModel,]
+SelectCompatiableValidators: TypeAlias = NoOptionsParameterValidatorModel
class SelectParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_select"] = "gx_select"
type: Literal["select"]
- options: Optional[List[LabelValue]] = None
+ options: list[LabelValue] | None = None
multiple: bool = False
- validators: List[SelectCompatiableValidators] = []
+ validators: list[SelectCompatiableValidators] = []
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
extra = kwargs["json_schema_extra"]
if self.options is not None and self.options:
@@ -1762,10 +1732,10 @@ class SelectParameterModel(BaseGalaxyToolParameterModelDefinition):
return data
- def py_type_if_required(self, allow_connections: bool = False) -> Type:
+ def py_type_if_required(self, allow_connections: bool = False) -> builtins.type:
if self.options is not None:
if len(self.options) > 0:
- literal_options: List[Type] = [cast_as_type(Literal[o.value]) for o in self.options]
+ literal_options = [cast(type, Literal[o.value]) for o in self.options]
py_type = union_type(literal_options)
else:
py_type = type(None)
@@ -1781,18 +1751,17 @@ class SelectParameterModel(BaseGalaxyToolParameterModelDefinition):
return py_type
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return optional_if_needed(self.py_type_if_required(), self.optional or self.multiple)
@property
- def py_type_workflow_step(self) -> Type:
+ def py_type_workflow_step(self) -> builtins.type:
# this is always optional in this context
return optional(self.py_type_if_required())
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
validators = {}
requires_value = self.request_requires_value
- py_type = None
if state_representation == "workflow_step":
py_type = self.py_type_workflow_step
elif state_representation == "workflow_step_linked":
@@ -1825,7 +1794,7 @@ class SelectParameterModel(BaseGalaxyToolParameterModelDefinition):
return self.options is not None and any(o.selected for o in self.options)
@property
- def default_value(self) -> Optional[str]:
+ def default_value(self) -> str | None:
assert not self.multiple
if self.options:
for option in self.options:
@@ -1838,7 +1807,7 @@ class SelectParameterModel(BaseGalaxyToolParameterModelDefinition):
return None
@property
- def default_values(self) -> Optional[List[str]]:
+ def default_values(self) -> list[str] | None:
assert self.multiple
if self.options:
return [option.value for option in self.options if option.selected]
@@ -1862,14 +1831,14 @@ class GenomeBuildParameterModel(BaseGalaxyToolParameterModelDefinition):
type: Literal["genomebuild"]
multiple: bool
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
kwargs["json_schema_extra"]["gx_multiple"] = self.multiple
return kwargs
@property
- def py_type(self) -> Type:
- py_type: Type = StrictStr
+ def py_type(self) -> builtins.type:
+ py_type: type = StrictStr
if self.multiple:
py_type = list_type(py_type)
return optional_if_needed(py_type, self.optional or self.multiple)
@@ -1891,8 +1860,8 @@ DrillDownHierarchyT = Literal["recurse", "exact"]
def drill_down_possible_values(
- options: List[DrillDownOptionsDict], multiple: bool, hierarchy: DrillDownHierarchyT
-) -> List[str]:
+ options: list[DrillDownOptionsDict], multiple: bool, hierarchy: DrillDownHierarchyT
+) -> list[str]:
possible_values = []
def add_value(option: str, is_leaf: bool):
@@ -1917,21 +1886,20 @@ def drill_down_possible_values(
class DrillDownParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_drill_down"] = "gx_drill_down"
type: Literal["drill_down"]
- options: Optional[List[DrillDownOptionsDict]] = None
+ options: list[DrillDownOptionsDict] | None = None
multiple: bool
hierarchy: DrillDownHierarchyT
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
kwargs["json_schema_extra"]["gx_multiple"] = self.multiple
return kwargs
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
if self.options is not None:
- literal_options: List[Type] = [
- cast_as_type(Literal[o])
- for o in drill_down_possible_values(self.options, self.multiple, self.hierarchy)
+ literal_options = [
+ cast(type, Literal[o]) for o in drill_down_possible_values(self.options, self.multiple, self.hierarchy)
]
py_type = union_type(literal_options)
else:
@@ -1943,7 +1911,7 @@ class DrillDownParameterModel(BaseGalaxyToolParameterModelDefinition):
return py_type
@property
- def py_type_test_case_xml(self) -> Type:
+ def py_type_test_case_xml(self) -> builtins.type:
base_model = str
return optional_if_needed(base_model, not self.request_requires_value)
@@ -1960,8 +1928,7 @@ class DrillDownParameterModel(BaseGalaxyToolParameterModelDefinition):
@property
def request_requires_value(self) -> bool:
- options = self.options
- if options:
+ if options := self.options:
# if any of these are selected, they seem to serve as defaults - check out test_tools -> test_drill_down_first_by_default
return not any_drill_down_options_selected(options)
else:
@@ -1970,25 +1937,23 @@ class DrillDownParameterModel(BaseGalaxyToolParameterModelDefinition):
return False
@property
- def default_option(self) -> Optional[str]:
- options = self.options
- if options:
+ def default_option(self) -> str | None:
+ if options := self.options:
selected_options = selected_drill_down_options(options)
if len(selected_options) > 0:
return selected_options[0]
return None
@property
- def default_options(self) -> Optional[List[str]]:
- options = self.options
- if options:
+ def default_options(self) -> list[str] | None:
+ if options := self.options:
selected_options = selected_drill_down_options(options)
return selected_options
return None
-def any_drill_down_options_selected(options: List[DrillDownOptionsDict]) -> bool:
+def any_drill_down_options_selected(options: list[DrillDownOptionsDict]) -> bool:
for option in options:
selected = option.get("selected")
if selected:
@@ -2000,8 +1965,8 @@ def any_drill_down_options_selected(options: List[DrillDownOptionsDict]) -> bool
return False
-def selected_drill_down_options(options: List[DrillDownOptionsDict]) -> List[str]:
- selected_options: List[str] = []
+def selected_drill_down_options(options: list[DrillDownOptionsDict]) -> list[str]:
+ selected_options: list[str] = []
for option in options:
selected = option.get("selected")
value = option.get("value")
@@ -2017,9 +1982,9 @@ class DataColumnParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_data_column"] = "gx_data_column"
type: Literal["data_column"]
multiple: bool
- value: Optional[Union[int, List[int]]] = None
+ value: int | list[int] | None = None
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
kwargs["json_schema_extra"]["gx_multiple"] = self.multiple
return kwargs
@@ -2034,10 +1999,8 @@ class DataColumnParameterModel(BaseGalaxyToolParameterModelDefinition):
return data
@property
- def py_type(self) -> Type:
- py_type: Type = StrictInt
- if self.multiple:
- py_type = list_type(py_type)
+ def py_type(self) -> builtins.type:
+ py_type = list_type(StrictInt) if self.multiple else StrictInt
return optional_if_needed(py_type, self.optional)
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2076,16 +2039,14 @@ class GroupTagParameterModel(BaseGalaxyToolParameterModelDefinition):
type: Literal["group_tag"]
multiple: bool
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
kwargs["json_schema_extra"]["gx_multiple"] = self.multiple
return kwargs
@property
- def py_type(self) -> Type:
- py_type: Type = StrictStr
- if self.multiple:
- py_type = list_type(py_type)
+ def py_type(self) -> builtins.type:
+ py_type = list_type(StrictStr) if self.multiple else StrictStr
return optional_if_needed(py_type, self.optional)
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2104,7 +2065,7 @@ class BaseUrlParameterModel(BaseGalaxyToolParameterModelDefinition):
type: Literal["baseurl"]
@property
- def py_type(self) -> Type:
+ def py_type(self) -> builtins.type:
return HttpUrl
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2115,13 +2076,13 @@ class BaseUrlParameterModel(BaseGalaxyToolParameterModelDefinition):
return True
-DiscriminatorType = Union[bool, str]
+DiscriminatorType = bool | str
def cond_test_parameter_default_value(
test_parameter: Union[BooleanParameterModel, "SelectParameterModel"],
-) -> Optional[DiscriminatorType]:
- default_value: Optional[DiscriminatorType] = None
+) -> DiscriminatorType | None:
+ default_value: DiscriminatorType | None = None
if isinstance(test_parameter, BooleanParameterModel):
default_value = test_parameter.value
elif isinstance(test_parameter, SelectParameterModel):
@@ -2133,17 +2094,17 @@ def cond_test_parameter_default_value(
class ConditionalWhen(StrictModel):
discriminator: DiscriminatorType
- parameters: List["ToolParameterT"]
+ parameters: list["ToolParameterT"]
is_default_when: bool
class ConditionalParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_conditional"] = "gx_conditional"
type: Literal["conditional"]
- test_parameter: Union[BooleanParameterModel, SelectParameterModel]
- whens: List[ConditionalWhen]
+ test_parameter: BooleanParameterModel | SelectParameterModel
+ whens: list[ConditionalWhen]
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
extra = kwargs["json_schema_extra"]
test_param = self.test_parameter
@@ -2164,7 +2125,7 @@ class ConditionalParameterModel(BaseGalaxyToolParameterModelDefinition):
test_parameter_requires_value = True
else:
test_parameter_requires_value = self.test_parameter.request_requires_value
- when_types: List[Type[BaseModel]] = []
+ when_types: list[type[BaseModel]] = []
default_type = None
for when in self.whens:
discriminator = when.discriminator
@@ -2177,7 +2138,7 @@ class ConditionalParameterModel(BaseGalaxyToolParameterModelDefinition):
extra_kwd = {test_param_name: (Literal[when.discriminator], initialize_test)}
when_types.append(
cast(
- Type[BaseModel],
+ type[BaseModel],
Annotated[
create_field_model(
parameters,
@@ -2202,9 +2163,9 @@ class ConditionalParameterModel(BaseGalaxyToolParameterModelDefinition):
extra_kwd=extra_kwd,
extra_validators={},
)
- when_types.append(cast(Type[BaseModel], Annotated[default_type, Tag("__absent__")]))
+ when_types.append(cast(type[BaseModel], Annotated[default_type, Tag("__absent__")]))
- def model_x_discriminator(v: Any) -> Optional[str]:
+ def model_x_discriminator(v: Any) -> str | None:
# returning None causes a validation error, this is what we would want if
# if the conditional state is not a dictionary.
if not isinstance(v, dict):
@@ -2220,7 +2181,7 @@ class ConditionalParameterModel(BaseGalaxyToolParameterModelDefinition):
else:
return str(test_param_val)
- py_type: Type
+ py_type: type
if len(when_types) > 1:
cond_type = union_type(when_types)
@@ -2259,11 +2220,11 @@ class ConditionalParameterModel(BaseGalaxyToolParameterModelDefinition):
class RepeatParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_repeat"] = "gx_repeat"
type: Literal["repeat"]
- parameters: List["ToolParameterT"]
- min: Optional[int] = None
- max: Optional[int] = None
+ parameters: list["ToolParameterT"]
+ min: int | None = None
+ max: int | None = None
- def field_kwargs(self) -> Dict[str, Any]:
+ def field_kwargs(self) -> dict[str, Any]:
kwargs = super().field_kwargs()
extra = kwargs["json_schema_extra"]
if self.min is not None:
@@ -2274,7 +2235,7 @@ class RepeatParameterModel(BaseGalaxyToolParameterModelDefinition):
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
# Maybe validators for min and max...
- instance_class: Type[BaseModel] = create_field_model(
+ instance_class: type[BaseModel] = create_field_model(
self.parameters, f"Repeat_{self.name}", state_representation
)
min_length = self.min
@@ -2293,7 +2254,7 @@ class RepeatParameterModel(BaseGalaxyToolParameterModelDefinition):
initialize_repeat = None
class RepeatType(RootModel):
- root: List[instance_class] = Field(initialize_repeat, min_length=min_length, max_length=max_length) # type: ignore[valid-type]
+ root: list[instance_class] = Field(initialize_repeat, min_length=min_length, max_length=max_length) # type: ignore[valid-type]
field_kwargs = self.field_kwargs()
return DynamicModelInformation(
@@ -2317,10 +2278,10 @@ class RepeatParameterModel(BaseGalaxyToolParameterModelDefinition):
class SectionParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["gx_section"] = "gx_section"
type: Literal["section"]
- parameters: List["ToolParameterT"]
+ parameters: list["ToolParameterT"]
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
- instance_class: Type[BaseModel] = create_field_model(
+ instance_class: type[BaseModel] = create_field_model(
self.parameters, f"Section_{self.name}", state_representation
)
requires_value = self.request_requires_value
@@ -2347,14 +2308,14 @@ class SectionParameterModel(BaseGalaxyToolParameterModelDefinition):
return any_request_parameters_required
-LiteralNone: Type = Literal[None] # type: ignore[assignment]
+LiteralNone: TypeAlias = Literal[None]
class CwlNullParameterModel(BaseToolParameterModelDefinition):
parameter_type: Literal["cwl_null"] = "cwl_null"
@property
- def py_type(self) -> Type:
+ def py_type(self) -> type:
return LiteralNone
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2373,7 +2334,7 @@ class CwlStringParameterModel(BaseToolParameterModelDefinition):
parameter_type: Literal["cwl_string"] = "cwl_string"
@property
- def py_type(self) -> Type:
+ def py_type(self) -> type:
return StrictStr
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2392,7 +2353,7 @@ class CwlIntegerParameterModel(BaseToolParameterModelDefinition):
parameter_type: Literal["cwl_integer"] = "cwl_integer"
@property
- def py_type(self) -> Type:
+ def py_type(self) -> type:
return StrictInt
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2411,7 +2372,7 @@ class CwlFloatParameterModel(BaseToolParameterModelDefinition):
parameter_type: Literal["cwl_float"] = "cwl_float"
@property
- def py_type(self) -> Type:
+ def py_type(self) -> type:
return union_type([StrictFloat, StrictInt])
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2430,7 +2391,7 @@ class CwlBooleanParameterModel(BaseToolParameterModelDefinition):
parameter_type: Literal["cwl_boolean"] = "cwl_boolean"
@property
- def py_type(self) -> Type:
+ def py_type(self) -> type:
return StrictBool
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2447,14 +2408,12 @@ class CwlBooleanParameterModel(BaseToolParameterModelDefinition):
class CwlUnionParameterModel(BaseToolParameterModelDefinition):
parameter_type: Literal["cwl_union"] = "cwl_union"
- parameters: List["CwlParameterT"]
+ parameters: list["CwlParameterT"]
@property
- def py_type(self) -> Type:
- union_of_cwl_types: List[Type] = []
- for parameter in self.parameters:
- union_of_cwl_types.append(parameter.py_type)
- return union_type(union_of_cwl_types)
+ def py_type(self) -> builtins.type:
+ cwl_types = [parameter.py_type for parameter in self.parameters]
+ return union_type(cwl_types)
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
return DynamicModelInformation(
@@ -2472,7 +2431,7 @@ class CwlFileParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["cwl_file"] = "cwl_file"
@property
- def py_type(self) -> Type:
+ def py_type(self) -> type:
return DataRequest
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2487,7 +2446,7 @@ class CwlDirectoryParameterModel(BaseGalaxyToolParameterModelDefinition):
parameter_type: Literal["cwl_directory"] = "cwl_directory"
@property
- def py_type(self) -> Type:
+ def py_type(self) -> type:
return DataRequest
def pydantic_template(self, state_representation: StateRepresentationT) -> DynamicModelInformation:
@@ -2498,43 +2457,40 @@ class CwlDirectoryParameterModel(BaseGalaxyToolParameterModelDefinition):
return True
-CwlParameterT = Union[
- CwlIntegerParameterModel,
- CwlFloatParameterModel,
- CwlStringParameterModel,
- CwlBooleanParameterModel,
- CwlNullParameterModel,
- CwlFileParameterModel,
- CwlDirectoryParameterModel,
- CwlUnionParameterModel,
-]
+CwlParameterT = (
+ CwlIntegerParameterModel
+ | CwlFloatParameterModel
+ | CwlStringParameterModel
+ | CwlBooleanParameterModel
+ | CwlNullParameterModel
+ | CwlFileParameterModel
+ | CwlDirectoryParameterModel
+ | CwlUnionParameterModel
+)
-GalaxyParameterT = Union[
- TextParameterModel,
- IntegerParameterModel,
- FloatParameterModel,
- BooleanParameterModel,
- HiddenParameterModel,
- SelectParameterModel,
- DataParameterModel,
- DataCollectionParameterModel,
- DataColumnParameterModel,
- DirectoryUriParameterModel,
- RulesParameterModel,
- DrillDownParameterModel,
- GroupTagParameterModel,
- BaseUrlParameterModel,
- GenomeBuildParameterModel,
- ColorParameterModel,
- ConditionalParameterModel,
- RepeatParameterModel,
- SectionParameterModel,
-]
+GalaxyParameterT = (
+ TextParameterModel
+ | IntegerParameterModel
+ | FloatParameterModel
+ | BooleanParameterModel
+ | HiddenParameterModel
+ | SelectParameterModel
+ | DataParameterModel
+ | DataCollectionParameterModel
+ | DataColumnParameterModel
+ | DirectoryUriParameterModel
+ | RulesParameterModel
+ | DrillDownParameterModel
+ | GroupTagParameterModel
+ | BaseUrlParameterModel
+ | GenomeBuildParameterModel
+ | ColorParameterModel
+ | ConditionalParameterModel
+ | RepeatParameterModel
+ | SectionParameterModel
+)
-ToolParameterT = Union[
- CwlParameterT,
- GalaxyParameterT,
-]
+ToolParameterT = CwlParameterT | GalaxyParameterT
class ToolParameterModel(RootModel):
@@ -2554,20 +2510,20 @@ CwlUnionParameterModel.model_rebuild()
class MaybeToolParameterBundle(Protocol):
"""An object that may or may not be a ToolParameterModel, but if it is a model, it has a root that is a ToolParameterT"""
- parameters: Optional[List[ToolParameterT]]
+ parameters: list[ToolParameterT] | None
class ToolParameterBundle(Protocol):
"""An object having a dictionary of input models (i.e. a 'Tool')"""
- parameters: List[ToolParameterT]
+ parameters: list[ToolParameterT]
class ToolParameterBundleModel(BaseModel):
- parameters: List[ToolParameterT]
+ parameters: list[ToolParameterT]
-def to_simple_model(input_parameter: Union[ToolParameterModel, ToolParameterT]) -> ToolParameterT:
+def to_simple_model(input_parameter: ToolParameterModel | ToolParameterT) -> ToolParameterT:
if input_parameter.__class__ == ToolParameterModel:
assert isinstance(input_parameter, ToolParameterModel)
return input_parameter.root
@@ -2576,7 +2532,7 @@ def to_simple_model(input_parameter: Union[ToolParameterModel, ToolParameterT])
def simple_input_models(
- parameters: Union[List[ToolParameterModel], List[ToolParameterT]],
+ parameters: list[ToolParameterModel] | list[ToolParameterT],
) -> Iterable[ToolParameterT]:
return [to_simple_model(m) for m in parameters]
@@ -2603,7 +2559,7 @@ def iter_parameter_models(parameters: Iterable[ToolParameterT]) -> Iterator[Tool
yield from iter_parameter_models(parameter.parameters)
-def create_model_strict(*args, **kwd) -> Type[BaseModel]:
+def create_model_strict(*args, **kwd) -> type[BaseModel]:
# protected_namespaces here prevents tool with model_ parameter names from issuing warnings
model_config = ConfigDict(extra="forbid", protected_namespaces=())
@@ -2612,7 +2568,7 @@ def create_model_strict(*args, **kwd) -> Type[BaseModel]:
def create_model_factory(state_representation: StateRepresentationT):
- def create_method(tool: ToolParameterBundle, name: Optional[str] = None) -> Type[BaseModel]:
+ def create_method(tool: ToolParameterBundle, name: str | None = None) -> type[BaseModel]:
return create_field_model(tool.parameters, name or DEFAULT_MODEL_NAME, state_representation)
return create_method
@@ -2633,13 +2589,13 @@ create_workflow_step_linked_model = create_model_factory("workflow_step_linked")
def create_field_model(
- tool_parameter_models: Union[List[ToolParameterModel], List[ToolParameterT]],
+ tool_parameter_models: list[ToolParameterModel] | list[ToolParameterT],
name: str,
state_representation: StateRepresentationT,
- extra_kwd: Optional[Mapping[str, tuple]] = None,
- extra_validators: Optional[ValidatorDictT] = None,
-) -> Type[BaseModel]:
- kwd: Dict[str, tuple] = {}
+ extra_kwd: Mapping[str, tuple] | None = None,
+ extra_validators: ValidatorDictT | None = None,
+) -> type[BaseModel]:
+ kwd: dict[str, tuple] = {}
if extra_kwd:
kwd.update(extra_kwd)
model_validators = (extra_validators or {}).copy()
diff --git a/lib/galaxy/tool_util_models/sample_sheet.py b/lib/galaxy/tool_util_models/sample_sheet.py
index 8edffda8225..3a237b2fcbb 100644
--- a/lib/galaxy/tool_util_models/sample_sheet.py
+++ b/lib/galaxy/tool_util_models/sample_sheet.py
@@ -6,10 +6,7 @@ These types are used across the codebase for sample sheet metadata in collection
from typing import (
Any,
- Dict,
- List,
- Optional,
- Union,
+ Literal,
)
from pydantic import (
@@ -17,7 +14,6 @@ from pydantic import (
with_config,
)
from typing_extensions import (
- Literal,
NotRequired,
TypedDict,
)
@@ -31,22 +27,22 @@ SampleSheetColumnType = Literal[
"string", "int", "float", "boolean", "element_identifier"
] # excluding "long" and "double" and composite types from CWL for now - we don't think at this level of abstraction in Galaxy generally
NoneType = type(None)
-SampleSheetColumnValueT = Union[int, float, bool, str, NoneType]
+SampleSheetColumnValueT = int | float | bool | str | NoneType
# type ignore because mypy can't handle closed TypedDicts yet
@with_config(ConfigDict(extra="forbid"))
class SampleSheetColumnDefinition(TypedDict, closed=True): # type: ignore[call-arg]
name: str
- description: NotRequired[Optional[str]]
+ description: NotRequired[str | None]
type: SampleSheetColumnType
optional: bool
- default_value: NotRequired[Optional[SampleSheetColumnValueT]]
- validators: NotRequired[Optional[List[Dict[str, Any]]]]
- restrictions: NotRequired[Optional[List[SampleSheetColumnValueT]]]
- suggestions: NotRequired[Optional[List[SampleSheetColumnValueT]]]
+ default_value: NotRequired[SampleSheetColumnValueT | None]
+ validators: NotRequired[list[dict[str, Any]] | None]
+ restrictions: NotRequired[list[SampleSheetColumnValueT] | None]
+ suggestions: NotRequired[list[SampleSheetColumnValueT] | None]
-SampleSheetColumnDefinitions = List[SampleSheetColumnDefinition]
-SampleSheetRow = List[SampleSheetColumnValueT]
-SampleSheetRows = Dict[str, SampleSheetRow]
+SampleSheetColumnDefinitions = list[SampleSheetColumnDefinition]
+SampleSheetRow = list[SampleSheetColumnValueT]
+SampleSheetRows = dict[str, SampleSheetRow]
diff --git a/lib/galaxy/tool_util_models/test_job.py b/lib/galaxy/tool_util_models/test_job.py
index f1495617b4e..debfd6e129b 100644
--- a/lib/galaxy/tool_util_models/test_job.py
+++ b/lib/galaxy/tool_util_models/test_job.py
@@ -11,10 +11,8 @@ left ``TestJob.job`` as ``Dict[str, Any]``.
"""
from typing import (
- Dict,
- List,
- Optional,
- Union,
+ Annotated,
+ Literal,
)
from pydantic import (
@@ -24,10 +22,6 @@ from pydantic import (
RootModel,
Tag,
)
-from typing_extensions import (
- Annotated,
- Literal,
-)
from ._base import (
CollectionType,
@@ -59,33 +53,33 @@ class BaseFile(_StrictJobModel):
model_config = ConfigDict(extra="forbid", populate_by_name=True, title="BaseFile")
class_: Literal["File"] = Field(alias="class", title="Class")
- filetype: Annotated[Optional[str], Field(title="File Type")] = None
- dbkey: Annotated[Optional[str], Field(title="Dbkey")] = None
- decompress: Annotated[Optional[bool], Field(title="Decompress")] = None
- to_posix_lines: Annotated[Optional[bool], Field(title="To POSIX Lines")] = None
- space_to_tab: Annotated[Optional[bool], Field(title="Space To Tab")] = None
- deferred: Annotated[Optional[bool], Field(title="Deferred")] = None
- name: Annotated[Optional[str], Field(title="Name")] = None
- info: Annotated[Optional[str], Field(title="Info")] = None
- tags: Annotated[Optional[List[str]], Field(title="Tags")] = None
- hashes: Annotated[Optional[List[HashEntry]], Field(title="Hashes")] = None
- identifier: Annotated[Optional[str], Field(title="Identifier")] = None
+ filetype: Annotated[str | None, Field(title="File Type")] = None
+ dbkey: Annotated[str | None, Field(title="Dbkey")] = None
+ decompress: Annotated[bool | None, Field(title="Decompress")] = None
+ to_posix_lines: Annotated[bool | None, Field(title="To POSIX Lines")] = None
+ space_to_tab: Annotated[bool | None, Field(title="Space To Tab")] = None
+ deferred: Annotated[bool | None, Field(title="Deferred")] = None
+ name: Annotated[str | None, Field(title="Name")] = None
+ info: Annotated[str | None, Field(title="Info")] = None
+ tags: Annotated[list[str] | None, Field(title="Tags")] = None
+ hashes: Annotated[list[HashEntry] | None, Field(title="Hashes")] = None
+ identifier: Annotated[str | None, Field(title="Identifier")] = None
class LocationFile(BaseFile):
model_config = ConfigDict(extra="forbid", populate_by_name=True, title="LocationFile")
location: Annotated[str, Field(title="Location")]
- path: Annotated[Optional[str], Field(title="Path")] = None
- contents: Annotated[Optional[str], Field(title="Contents")] = None
- composite_data: Annotated[Optional[List[str]], Field(title="Composite Data")] = None
+ path: Annotated[str | None, Field(title="Path")] = None
+ contents: Annotated[str | None, Field(title="Contents")] = None
+ composite_data: Annotated[list[str] | None, Field(title="Composite Data")] = None
class PathFile(BaseFile):
model_config = ConfigDict(extra="forbid", populate_by_name=True, title="PathFile")
path: Annotated[str, Field(title="Path")]
- location: Annotated[Optional[str], Field(title="Location")] = None
- contents: Annotated[Optional[str], Field(title="Contents")] = None
- composite_data: Annotated[Optional[List[str]], Field(title="Composite Data")] = None
+ location: Annotated[str | None, Field(title="Location")] = None
+ contents: Annotated[str | None, Field(title="Contents")] = None
+ composite_data: Annotated[list[str] | None, Field(title="Composite Data")] = None
class ContentsFile(BaseFile):
@@ -93,17 +87,17 @@ class ContentsFile(BaseFile):
model_config = ConfigDict(extra="forbid", populate_by_name=True, title="ContentsFile")
contents: Annotated[str, Field(title="Contents")]
- path: Annotated[Optional[str], Field(title="Path")] = None
- location: Annotated[Optional[str], Field(title="Location")] = None
- composite_data: Annotated[Optional[List[str]], Field(title="Composite Data")] = None
+ path: Annotated[str | None, Field(title="Path")] = None
+ location: Annotated[str | None, Field(title="Location")] = None
+ composite_data: Annotated[list[str] | None, Field(title="Composite Data")] = None
class CompositeDataFile(BaseFile):
model_config = ConfigDict(extra="forbid", populate_by_name=True, title="CompositeDataFile")
- composite_data: Annotated[List[str], Field(title="Composite Data")]
- path: Annotated[Optional[str], Field(title="Path")] = None
- location: Annotated[Optional[str], Field(title="Location")] = None
- contents: Annotated[Optional[str], Field(title="Contents")] = None
+ composite_data: Annotated[list[str], Field(title="Composite Data")]
+ path: Annotated[str | None, Field(title="Path")] = None
+ location: Annotated[str | None, Field(title="Location")] = None
+ contents: Annotated[str | None, Field(title="Contents")] = None
def _discriminate_file(v):
@@ -129,12 +123,10 @@ def _discriminate_file(v):
File = Annotated[
- Union[
- Annotated[LocationFile, Tag("location")],
- Annotated[PathFile, Tag("path")],
- Annotated[ContentsFile, Tag("contents")],
- Annotated[CompositeDataFile, Tag("composite_data")],
- ],
+ Annotated[LocationFile, Tag("location")]
+ | Annotated[PathFile, Tag("path")]
+ | Annotated[ContentsFile, Tag("contents")]
+ | Annotated[CompositeDataFile, Tag("composite_data")],
Discriminator(_discriminate_file),
]
@@ -143,14 +135,14 @@ class Collection(_StrictJobModel):
model_config = ConfigDict(extra="forbid", populate_by_name=True, title="Collection")
class_: Literal["Collection"] = Field(alias="class", title="Class")
collection_type: Annotated[CollectionType, Field(title="Collection Type")] = None
- name: Annotated[Optional[str], Field(title="Name")] = None
- identifier: Annotated[Optional[str], Field(title="Identifier")] = None
- elements: Annotated[Optional[List["CollectionElement"]], Field(title="Elements")] = None
- rows: Annotated[Optional[Dict[str, list]], Field(title="Rows")] = None
+ name: Annotated[str | None, Field(title="Name")] = None
+ identifier: Annotated[str | None, Field(title="Identifier")] = None
+ elements: Annotated[list["CollectionElement"] | None, Field(title="Elements")] = None
+ rows: Annotated[dict[str, list] | None, Field(title="Rows")] = None
CollectionElement = Annotated[
- Union[File, Collection],
+ File | Collection,
Field(discriminator="class_"),
]
@@ -165,10 +157,10 @@ class Directory(_StrictJobModel):
model_config = ConfigDict(extra="forbid", populate_by_name=True, title="Directory")
class_: Literal["Directory"] = Field(alias="class", title="Class")
- path: Annotated[Optional[str], Field(title="Path")] = None
- location: Annotated[Optional[str], Field(title="Location")] = None
- filetype: Annotated[Optional[str], Field(title="File Type")] = None
- name: Annotated[Optional[str], Field(title="Name")] = None
+ path: Annotated[str | None, Field(title="Path")] = None
+ location: Annotated[str | None, Field(title="Location")] = None
+ filetype: Annotated[str | None, Field(title="File Type")] = None
+ name: Annotated[str | None, Field(title="Name")] = None
# JobParamValue is non-recursive at the list axis: a job-param list may contain
@@ -176,18 +168,10 @@ class Directory(_StrictJobModel):
# collections) is recursive via ``CollectionElement``. No observed workflow
# test value needs a list-of-lists at the job-input level; widen explicitly if
# that changes rather than defaulting to Any.
-JobParamValue = Union[
- File,
- Collection,
- Directory,
- str,
- int,
- float,
- bool,
- None,
- List[Union[File, str, int, float, bool, None]],
-]
+JobParamValue = (
+ File | Collection | Directory | str | int | float | bool | None | list[File | str | int | float | bool | None]
+)
-class Job(RootModel[Dict[str, JobParamValue]]):
+class Job(RootModel[dict[str, JobParamValue]]):
model_config = ConfigDict(title="Job")
diff --git a/lib/galaxy/tool_util_models/testing_types.py b/lib/galaxy/tool_util_models/testing_types.py
index cb27a87762d..e6066a67faa 100644
--- a/lib/galaxy/tool_util_models/testing_types.py
+++ b/lib/galaxy/tool_util_models/testing_types.py
@@ -6,9 +6,6 @@ These live in ``tool_util_models`` so both ``tool_util_models`` and
from typing import (
Any,
- Dict,
- List,
- Optional,
)
from typing_extensions import TypedDict
@@ -16,11 +13,11 @@ from typing_extensions import TypedDict
class AssertionDict(TypedDict):
tag: str
- attributes: Dict[str, Any]
+ attributes: dict[str, Any]
children: "AssertionList"
-AssertionList = Optional[List[AssertionDict]]
+AssertionList = list[AssertionDict] | None
class DirectCredentialValue(TypedDict):
@@ -32,8 +29,8 @@ class DirectCredentialValue(TypedDict):
class _DirectCredentialRequired(TypedDict):
name: str
- variables: List[DirectCredentialValue]
- secrets: List[DirectCredentialValue]
+ variables: list[DirectCredentialValue]
+ secrets: list[DirectCredentialValue]
class DirectCredential(_DirectCredentialRequired, total=False):
diff --git a/lib/galaxy/tool_util_models/tool_outputs.py b/lib/galaxy/tool_util_models/tool_outputs.py
index b044f84e0a3..f6db3cbd736 100644
--- a/lib/galaxy/tool_util_models/tool_outputs.py
+++ b/lib/galaxy/tool_util_models/tool_outputs.py
@@ -6,12 +6,10 @@ code where actual tool objects aren't created.
"""
from typing import (
+ Annotated,
Any,
- Dict,
Generic,
- List,
- Optional,
- Union,
+ Literal,
)
from pydantic import (
@@ -20,15 +18,11 @@ from pydantic import (
model_validator,
)
from typing_extensions import (
- Annotated,
- Literal,
TypeVar,
)
from ._base import ToolSourceBaseModel
-AnyT = TypeVar("AnyT")
-NotRequired = Optional[AnyT]
IncomingNotRequiredBoolT = TypeVar("IncomingNotRequiredBoolT")
IncomingNotRequiredStringT = TypeVar("IncomingNotRequiredStringT")
@@ -39,7 +33,7 @@ class GenericToolOutputBaseModel(ToolSourceBaseModel, Generic[IncomingNotRequire
name: Annotated[
IncomingNotRequiredStringT, Field(description="Parameter name. Used when referencing parameter in workflows.")
]
- label: Annotated[Optional[str], Field(description="Output label. Will be used as dataset name in history.")] = None
+ label: Annotated[str | None, Field(description="Output label. Will be used as dataset name in history.")] = None
hidden: Annotated[
IncomingNotRequiredBoolT, Field(description="If true, the output will not be shown in the history.")
]
@@ -60,10 +54,10 @@ class DatasetCollectionDescription(ToolSourceBaseModel):
model_config = ConfigDict(extra="forbid")
discover_via: DiscoverViaT
- format: Optional[str] = None
+ format: str | None = None
visible: bool = False
assign_primary_output: bool = False
- directory: Optional[str] = None
+ directory: str | None = None
recurse: bool = False
match_relative_path: bool = False
@@ -85,7 +79,7 @@ class FilePatternDatasetCollectionDescription(DatasetCollectionDescription):
pattern: str
-DatasetCollectionDescriptionT = Union[FilePatternDatasetCollectionDescription, ToolProvidedMetadataDatasetCollection]
+DatasetCollectionDescriptionT = FilePatternDatasetCollectionDescription | ToolProvidedMetadataDatasetCollection
class GenericToolOutputDataset(
@@ -95,45 +89,40 @@ class GenericToolOutputDataset(
type: Literal["data"]
format: Annotated[IncomingNotRequiredStringT, Field(description="The short name for the output datatype.")]
format_source: Annotated[
- Optional[str],
+ str | None,
Field(
description="This sets the data type of the output dataset(s) to be the same format as that of the specified tool input."
),
] = None
metadata_source: Annotated[
- Optional[str],
+ str | None,
Field(
description="This copies the metadata information from the tool’s input dataset to serve as default for information that cannot be detected from the output. One prominent use case is interval data with a non-standard column order that cannot be deduced from a header line, but which is known to be identical in the input and output datasets."
),
] = None
- discover_datasets: Optional[List[DatasetCollectionDescriptionT]] = None
+ discover_datasets: list[DatasetCollectionDescriptionT] | None = None
from_work_dir: Annotated[
- Optional[str],
+ str | None,
Field(
title="from_work_dir",
description="Relative path to a file produced by the tool in its working directory. Output’s contents are set to this file’s contents.",
),
] = None
- precreate_directory: Optional[bool] = False
+ precreate_directory: bool | None = False
class ToolOutputDataset(GenericToolOutputDataset[bool, str]): ...
-class IncomingToolOutputDataset(
- GenericToolOutputDataset[
- NotRequired[bool],
- NotRequired[str],
- ]
-):
- name: Annotated[
- Optional[str], Field(description="Parameter name. Used when referencing parameter in workflows.")
- ] = None
- hidden: Annotated[Optional[bool], Field(description="If true, the output will not be shown in the history.")] = None
- format: Annotated[Optional[str], Field(description="The short name for the output datatype.")] = None
+class IncomingToolOutputDataset(GenericToolOutputDataset[bool | None, str | None]):
+ name: Annotated[str | None, Field(description="Parameter name. Used when referencing parameter in workflows.")] = (
+ None
+ )
+ hidden: Annotated[bool | None, Field(description="If true, the output will not be shown in the history.")] = None
+ format: Annotated[str | None, Field(description="The short name for the output datatype.")] = None
-def lift_legacy_collection_structure(output_dict: Dict[str, Any]) -> Dict[str, Any]:
+def lift_legacy_collection_structure(output_dict: dict[str, Any]) -> dict[str, Any]:
# Older DynamicTool.value rows nest collection fields under ``structure:``;
# the current model expects them flat on the output. Inline them so the
# parser and pydantic model both see the same flat form. Top-level keys
@@ -155,11 +144,11 @@ class GenericToolOutputCollection(
Generic[IncomingNotRequiredBoolT, IncomingNotRequiredStringT],
):
type: Literal["collection"]
- collection_type: Optional[str] = None
- collection_type_source: Optional[str] = None
- collection_type_from_rules: Optional[str] = None
- structured_like: Optional[str] = None
- discover_datasets: Optional[List[DatasetCollectionDescriptionT]] = None
+ collection_type: str | None = None
+ collection_type_source: str | None = None
+ collection_type_from_rules: str | None = None
+ structured_like: str | None = None
+ discover_datasets: list[DatasetCollectionDescriptionT] | None = None
@model_validator(mode="before")
@classmethod
@@ -172,11 +161,11 @@ class GenericToolOutputCollection(
class ToolOutputCollection(GenericToolOutputCollection[bool, str]): ...
-class IncomingToolOutputCollection(GenericToolOutputCollection[NotRequired[bool], NotRequired[str]]):
- name: Annotated[
- Optional[str], Field(description="Parameter name. Used when referencing parameter in workflows.")
- ] = None
- hidden: Annotated[Optional[bool], Field(description="If true, the output will not be shown in the history.")] = None
+class IncomingToolOutputCollection(GenericToolOutputCollection[bool | None, str | None]):
+ name: Annotated[str | None, Field(description="Parameter name. Used when referencing parameter in workflows.")] = (
+ None
+ )
+ hidden: Annotated[bool | None, Field(description="If true, the output will not be shown in the history.")] = None
class GenericToolOutputSimple(
@@ -212,8 +201,8 @@ class ToolOutputBoolean(GenericToolOutputSimple[bool, str]):
# be referenced. Previously these reused the strict types above, whose unbound type
# vars also forced ``hidden`` to be required -- a bug that made the published schema
# demand a ``hidden`` flag on every simple output.
-class IncomingToolOutputSimple(GenericToolOutputSimple[NotRequired[bool], str]):
- hidden: Annotated[Optional[bool], Field(description="If true, the output will not be shown in the history.")] = None
+class IncomingToolOutputSimple(GenericToolOutputSimple[bool | None, str]):
+ hidden: Annotated[bool | None, Field(description="If true, the output will not be shown in the history.")] = None
class IncomingToolOutputText(IncomingToolOutputSimple):
@@ -232,16 +221,16 @@ class IncomingToolOutputBoolean(IncomingToolOutputSimple):
type: Literal["boolean"]
-IncomingToolOutputT = Union[
- IncomingToolOutputDataset,
- IncomingToolOutputCollection,
- IncomingToolOutputText,
- IncomingToolOutputInteger,
- IncomingToolOutputFloat,
- IncomingToolOutputBoolean,
-]
+IncomingToolOutputT = (
+ IncomingToolOutputDataset
+ | IncomingToolOutputCollection
+ | IncomingToolOutputText
+ | IncomingToolOutputInteger
+ | IncomingToolOutputFloat
+ | IncomingToolOutputBoolean
+)
IncomingToolOutput = Annotated[IncomingToolOutputT, Field(discriminator="type")]
-ToolOutputT = Union[
- ToolOutputDataset, ToolOutputCollection, ToolOutputText, ToolOutputInteger, ToolOutputFloat, ToolOutputBoolean
-]
+ToolOutputT = (
+ ToolOutputDataset | ToolOutputCollection | ToolOutputText | ToolOutputInteger | ToolOutputFloat | ToolOutputBoolean
+)
ToolOutput = Annotated[ToolOutputT, Field(discriminator="type")]
diff --git a/lib/galaxy/tool_util_models/tool_source.py b/lib/galaxy/tool_util_models/tool_source.py
index 881097f4913..7e0da4a6a90 100644
--- a/lib/galaxy/tool_util_models/tool_source.py
+++ b/lib/galaxy/tool_util_models/tool_source.py
@@ -1,8 +1,8 @@
import re
from enum import Enum
from typing import (
- List,
- Optional,
+ Annotated,
+ Literal,
Union,
)
@@ -14,8 +14,6 @@ from pydantic import (
)
from pydantic_core import PydanticCustomError
from typing_extensions import (
- Annotated,
- Literal,
NotRequired,
TypedDict,
)
@@ -40,7 +38,7 @@ class ContainerRequirement(ToolSourceBaseModel):
class PackageRequirement(Requirement):
type: Literal["package"]
name: str
- version: Optional[str] = None
+ version: str | None = None
class SetEnvironmentRequirement(Requirement):
@@ -58,7 +56,7 @@ ram_max_description = "Maximum reserved RAM in mebibytes (2**20)."
ram_description = """May be a fractional value. If so, the actual RAM request is rounded up to the next whole number. The reported amount of RAM reserved for the process is a non-zero integer."""
-ResourceRequirementValue = Union[int, float, str, None]
+ResourceRequirementValue = int | float | str | None
class ResourceRequirement(ToolSourceBaseModel):
@@ -87,8 +85,8 @@ class ResourceRequirement(ToolSourceBaseModel):
class JavascriptRequirement(ToolSourceBaseModel):
type: Literal["javascript"]
- expression_lib: Optional[
- List[
+ expression_lib: None | (
+ list[
Annotated[
str,
Field(
@@ -104,7 +102,7 @@ class JavascriptRequirement(ToolSourceBaseModel):
),
]
]
- ]
+ )
class XrefDict(TypedDict):
@@ -114,20 +112,20 @@ class XrefDict(TypedDict):
class TemplateConfigFile(ToolSourceBaseModel):
content: str
- name: Optional[str] = None
- filename: Optional[str] = None
+ name: str | None = None
+ filename: str | None = None
class InputConfigFileContent(ToolSourceBaseModel):
format: Literal["json"] = "json"
- handle_files: Optional[Literal["paths", "staging_path_and_source_path"]] = None
+ handle_files: Literal["paths", "staging_path_and_source_path"] | None = None
type: Literal["inputs"] = "inputs"
class InputConfigFile(ToolSourceBaseModel):
- name: Optional[str] = None
+ name: str | None = None
content: InputConfigFileContent
- filename: Optional[str] = None
+ filename: str | None = None
class FileSourceConfigFileContent(ToolSourceBaseModel):
@@ -135,8 +133,8 @@ class FileSourceConfigFileContent(ToolSourceBaseModel):
class FileSourceConfigFile(ToolSourceBaseModel):
- name: Optional[str]
- filename: Optional[str] = None
+ name: str | None
+ filename: str | None = None
content: FileSourceConfigFileContent
@@ -209,27 +207,27 @@ class HelpContent(ToolSourceBaseModel):
content: str
-StdioExitCodeRangeValue = Union[int, float, Literal["-inf", "inf"]]
+StdioExitCodeRangeValue = int | float | Literal["-inf", "inf"]
class StdioExitCode(ToolSourceBaseModel):
range_start: StdioExitCodeRangeValue
range_end: StdioExitCodeRangeValue
- error_level: Union[int, float]
- desc: Optional[str] = None
+ error_level: int | float
+ desc: str | None = None
class StdioRegex(ToolSourceBaseModel):
match: str
stdout_match: bool
stderr_match: bool
- error_level: Union[int, float]
- desc: Optional[str] = None
+ error_level: int | float
+ desc: str | None = None
class Stdio(ToolSourceBaseModel):
- exit_codes: List[StdioExitCode] = Field(default_factory=list)
- regexes: List[StdioRegex] = Field(default_factory=list)
+ exit_codes: list[StdioExitCode] = Field(default_factory=list)
+ regexes: list[StdioRegex] = Field(default_factory=list)
class OutputCompareType(str, Enum):
@@ -242,16 +240,16 @@ class OutputCompareType(str, Enum):
class DrillDownOptionsDict(TypedDict):
- name: Optional[str]
+ name: str | None
value: str
- options: List["DrillDownOptionsDict"]
+ options: list["DrillDownOptionsDict"]
selected: bool
# For fields... just implementing a subset of CWL for Galaxy flavors of these objects
# so far.
CwlType = Literal["File", "null", "boolean", "int", "float", "string"]
-FieldType = Union[CwlType, List[CwlType]]
+FieldType = CwlType | list[CwlType]
# type ignore because mypy can't handle closed TypedDicts yet
@@ -259,20 +257,20 @@ FieldType = Union[CwlType, List[CwlType]]
class FieldDict(TypedDict, closed=True): # type: ignore[call-arg]
name: str
type: FieldType
- format: NotRequired[Optional[str]]
+ format: NotRequired[str | None]
JsonTestDatasetDefDict = TypedDict(
"JsonTestDatasetDefDict",
{
"class": Literal["File"],
- "path": NotRequired[Optional[str]],
- "location": NotRequired[Optional[str]],
- "name": NotRequired[Optional[str]],
- "dbkey": NotRequired[Optional[str]],
- "filetype": NotRequired[Optional[str]],
- "composite_data": NotRequired[Optional[List[str]]],
- "tags": NotRequired[Optional[List[str]]],
+ "path": NotRequired[str | None],
+ "location": NotRequired[str | None],
+ "name": NotRequired[str | None],
+ "dbkey": NotRequired[str | None],
+ "filetype": NotRequired[str | None],
+ "composite_data": NotRequired[list[str] | None],
+ "tags": NotRequired[list[str] | None],
},
)
@@ -285,13 +283,13 @@ JsonTestCollectionDefDatasetElementDict = TypedDict(
{
"identifier": str,
"class": Literal["File"],
- "path": NotRequired[Optional[str]],
- "location": NotRequired[Optional[str]],
- "name": NotRequired[Optional[str]],
- "dbkey": NotRequired[Optional[str]],
- "filetype": NotRequired[Optional[str]],
- "composite_data": NotRequired[Optional[List[str]]],
- "tags": NotRequired[Optional[List[str]]],
+ "path": NotRequired[str | None],
+ "location": NotRequired[str | None],
+ "name": NotRequired[str | None],
+ "dbkey": NotRequired[str | None],
+ "filetype": NotRequired[str | None],
+ "composite_data": NotRequired[list[str] | None],
+ "tags": NotRequired[list[str] | None],
},
)
@@ -299,8 +297,8 @@ BaseJsonTestCollectionDefCollectionElementDict = TypedDict(
"BaseJsonTestCollectionDefCollectionElementDict",
{
"class": Literal["Collection"],
- "collection_type": Optional[str],
- "elements": NotRequired[Optional[List[JsonTestCollectionDefElementDict]]],
+ "collection_type": str | None,
+ "elements": NotRequired[list[JsonTestCollectionDefElementDict] | None],
},
)
@@ -309,8 +307,8 @@ JsonTestCollectionDefCollectionElementDict = TypedDict(
{
"identifier": str,
"class": Literal["Collection"],
- "collection_type": Optional[str],
- "elements": NotRequired[Optional[List[JsonTestCollectionDefElementDict]]],
+ "collection_type": str | None,
+ "elements": NotRequired[list[JsonTestCollectionDefElementDict] | None],
},
)
@@ -318,9 +316,9 @@ JsonTestCollectionDefDict = TypedDict(
"JsonTestCollectionDefDict",
{
"class": Literal["Collection"],
- "collection_type": Optional[str],
- "elements": NotRequired[Optional[List[JsonTestCollectionDefElementDict]]],
- "name": NotRequired[Optional[str]],
- "fields": NotRequired[Optional[List[FieldDict]]],
+ "collection_type": str | None,
+ "elements": NotRequired[list[JsonTestCollectionDefElementDict] | None],
+ "name": NotRequired[str | None],
+ "fields": NotRequired[list[FieldDict] | None],
},
)
diff --git a/lib/galaxy/tool_util_models/yaml_parameters.py b/lib/galaxy/tool_util_models/yaml_parameters.py
index efcc1774380..c535e2e7909 100644
--- a/lib/galaxy/tool_util_models/yaml_parameters.py
+++ b/lib/galaxy/tool_util_models/yaml_parameters.py
@@ -14,9 +14,9 @@ is not load-bearing for execution today.
"""
from typing import (
- List,
- Optional,
- Union,
+ Annotated,
+ Literal,
+ TypeAlias,
)
from pydantic import (
@@ -26,10 +26,6 @@ from pydantic import (
field_validator,
RootModel,
)
-from typing_extensions import (
- Annotated,
- Literal,
-)
from .parameter_validators import (
EmptyFieldParameterValidatorModel,
@@ -69,21 +65,19 @@ class YamlLabelValue(BaseModel):
# Narrow validator unions — drops XML-only validators like Expression.
-YamlTextValidators = Union[
- LengthParameterValidatorModel,
- RegexParameterValidatorModel,
- EmptyFieldParameterValidatorModel,
-]
-YamlNumberValidators = Union[InRangeParameterValidatorModel,]
-YamlSelectValidators = Union[NoOptionsParameterValidatorModel,]
+YamlTextValidators: TypeAlias = (
+ LengthParameterValidatorModel | RegexParameterValidatorModel | EmptyFieldParameterValidatorModel
+)
+YamlNumberValidators: TypeAlias = InRangeParameterValidatorModel
+YamlSelectValidators: TypeAlias = NoOptionsParameterValidatorModel
class _YamlParamBase(BaseModel):
model_config = ConfigDict(extra="forbid", populate_by_name=True)
name: str
- label: Optional[str] = None
- help: Optional[str] = None
+ label: str | None = None
+ help: str | None = None
optional: bool = False
@@ -98,7 +92,7 @@ def _common_internal_kwargs(yaml_param: "_YamlParamBase") -> dict:
class YamlBooleanParameter(_YamlParamBase):
type: Literal["boolean"]
- value: Optional[bool] = False
+ value: bool | None = False
def to_internal(self) -> BooleanParameterModel:
return BooleanParameterModel(type="boolean", value=self.value, **_common_internal_kwargs(self))
@@ -106,10 +100,10 @@ class YamlBooleanParameter(_YamlParamBase):
class YamlIntegerParameter(_YamlParamBase):
type: Literal["integer"]
- value: Optional[int] = None
- min: Optional[int] = None
- max: Optional[int] = None
- validators: List[YamlNumberValidators] = []
+ value: int | None = None
+ min: int | None = None
+ max: int | None = None
+ validators: list[YamlNumberValidators] = []
def to_internal(self) -> IntegerParameterModel:
return IntegerParameterModel(
@@ -124,10 +118,10 @@ class YamlIntegerParameter(_YamlParamBase):
class YamlFloatParameter(_YamlParamBase):
type: Literal["float"]
- value: Optional[float] = None
- min: Optional[float] = None
- max: Optional[float] = None
- validators: List[YamlNumberValidators] = []
+ value: float | None = None
+ min: float | None = None
+ max: float | None = None
+ validators: list[YamlNumberValidators] = []
def to_internal(self) -> FloatParameterModel:
return FloatParameterModel(
@@ -142,9 +136,9 @@ class YamlFloatParameter(_YamlParamBase):
class YamlTextParameter(_YamlParamBase):
type: Literal["text"]
- value: Optional[str] = Field(default=None, alias="value")
+ value: str | None = Field(default=None, alias="value")
area: bool = False
- validators: List[YamlTextValidators] = []
+ validators: list[YamlTextValidators] = []
def to_internal(self) -> TextParameterModel:
return TextParameterModel(
@@ -158,9 +152,9 @@ class YamlTextParameter(_YamlParamBase):
class YamlSelectParameter(_YamlParamBase):
type: Literal["select"]
- options: Annotated[List[YamlLabelValue], Field(min_length=1)]
+ options: Annotated[list[YamlLabelValue], Field(min_length=1)]
multiple: bool = False
- validators: List[YamlSelectValidators] = []
+ validators: list[YamlSelectValidators] = []
def to_internal(self) -> SelectParameterModel:
return SelectParameterModel(
@@ -174,7 +168,7 @@ class YamlSelectParameter(_YamlParamBase):
class YamlColorParameter(_YamlParamBase):
type: Literal["color"]
- value: Optional[str] = None
+ value: str | None = None
def to_internal(self) -> ColorParameterModel:
return ColorParameterModel(type="color", value=self.value, **_common_internal_kwargs(self))
@@ -190,7 +184,7 @@ def _split_format(v):
class YamlDataParameter(_YamlParamBase):
type: Literal["data"]
- format: List[str] = ["data"]
+ format: list[str] = ["data"]
multiple: Annotated[
bool,
Field(description="Set true to accept several datasets (a list) for this input instead of one."),
@@ -219,8 +213,8 @@ class YamlDataParameter(_YamlParamBase):
class YamlDataCollectionParameter(_YamlParamBase):
type: Literal["data_collection"]
- collection_type: Optional[str] = None
- format: List[str] = ["data"]
+ collection_type: str | None = None
+ format: list[str] = ["data"]
@field_validator("format", mode="before")
@classmethod
@@ -237,25 +231,25 @@ class YamlDataCollectionParameter(_YamlParamBase):
)
-YamlConditionalTestParameter = Annotated[Union[YamlBooleanParameter, YamlSelectParameter], Field(discriminator="type")]
+YamlConditionalTestParameter = Annotated[YamlBooleanParameter | YamlSelectParameter, Field(discriminator="type")]
class YamlConditionalWhen(BaseModel):
model_config = ConfigDict(extra="forbid", populate_by_name=True)
- discriminator: Union[bool, str]
- parameters: List["YamlGalaxyToolParameter"] = []
+ discriminator: bool | str
+ parameters: list["YamlGalaxyToolParameter"] = []
class YamlConditionalParameter(_YamlParamBase):
type: Literal["conditional"]
test_parameter: YamlConditionalTestParameter
- whens: Annotated[List[YamlConditionalWhen], Field(min_length=1)]
+ whens: Annotated[list[YamlConditionalWhen], Field(min_length=1)]
def to_internal(self) -> ConditionalParameterModel:
internal_test = self.test_parameter.to_internal()
default_value = cond_test_parameter_default_value(internal_test)
- internal_whens: List[ConditionalWhen] = []
+ internal_whens: list[ConditionalWhen] = []
for when in self.whens:
internal_params = [p.root.to_internal() for p in when.parameters]
internal_whens.append(
@@ -275,9 +269,9 @@ class YamlConditionalParameter(_YamlParamBase):
class YamlRepeatParameter(_YamlParamBase):
type: Literal["repeat"]
- parameters: List["YamlGalaxyToolParameter"] = []
- min: Optional[int] = None
- max: Optional[int] = None
+ parameters: list["YamlGalaxyToolParameter"] = []
+ min: int | None = None
+ max: int | None = None
def to_internal(self) -> RepeatParameterModel:
return RepeatParameterModel(
@@ -291,7 +285,7 @@ class YamlRepeatParameter(_YamlParamBase):
class YamlSectionParameter(_YamlParamBase):
type: Literal["section"]
- parameters: List["YamlGalaxyToolParameter"] = []
+ parameters: list["YamlGalaxyToolParameter"] = []
def to_internal(self) -> SectionParameterModel:
return SectionParameterModel(
@@ -301,19 +295,19 @@ class YamlSectionParameter(_YamlParamBase):
)
-YamlGalaxyParameterT = Union[
- YamlBooleanParameter,
- YamlIntegerParameter,
- YamlFloatParameter,
- YamlTextParameter,
- YamlSelectParameter,
- YamlColorParameter,
- YamlDataParameter,
- YamlDataCollectionParameter,
- YamlConditionalParameter,
- YamlRepeatParameter,
- YamlSectionParameter,
-]
+YamlGalaxyParameterT = (
+ YamlBooleanParameter
+ | YamlIntegerParameter
+ | YamlFloatParameter
+ | YamlTextParameter
+ | YamlSelectParameter
+ | YamlColorParameter
+ | YamlDataParameter
+ | YamlDataCollectionParameter
+ | YamlConditionalParameter
+ | YamlRepeatParameter
+ | YamlSectionParameter
+)
class YamlGalaxyToolParameter(RootModel):
diff --git a/lib/galaxy/tools/__init__.py b/lib/galaxy/tools/__init__.py
index 8746ee67a31..38aa52ae2f2 100644
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -21,7 +21,6 @@ from typing import (
NamedTuple,
Optional,
TYPE_CHECKING,
- Union,
)
from urllib.parse import unquote_plus
from uuid import UUID
@@ -398,7 +397,7 @@ class RawToolSource(NamedTuple):
tool_source_class: str
-def get_safe_version(tool: "Tool", requested_tool_version: str) -> Optional[str]:
+def get_safe_version(tool: "Tool", requested_tool_version: str) -> str | None:
if tool.id:
safe_version = WORKFLOW_SAFE_TOOL_VERSION_UPDATES.get(tool.id)
if (
@@ -417,9 +416,9 @@ class ToolNotFoundException(Exception):
pass
-def create_tool_from_source(app, tool_source: ToolSource, config_file: Optional[StrPath] = None, **kwds):
+def create_tool_from_source(app, tool_source: ToolSource, config_file: StrPath | None = None, **kwds):
# Allow specifying a different tool subclass to instantiate
- ToolClass: Optional[type[Tool]] = None
+ ToolClass: type[Tool] | None = None
if tool_source.parse_class() == "GalaxyUserTool":
ToolClass = UserDefinedTool
elif (tool_module := tool_source.parse_tool_module()) is not None:
@@ -445,9 +444,9 @@ def create_tool_from_source(app, tool_source: ToolSource, config_file: Optional[
def create_tool_from_representation(
app,
raw_tool_source: str,
- tool_dir: Optional[StrPath] = None,
+ tool_dir: StrPath | None = None,
tool_source_class="XmlToolSource",
- guid: Optional[str] = None,
+ guid: str | None = None,
) -> "Tool":
tool_source = get_tool_source(tool_source_class=tool_source_class, raw_tool_source=raw_tool_source)
return create_tool_from_source(app, tool_source=tool_source, tool_dir=tool_dir, guid=guid)
@@ -626,11 +625,11 @@ class ToolBox(AbstractToolBox):
def _create_tool_from_source(self, tool_source: ToolSource, **kwds):
return create_tool_from_source(self.app, tool_source, **kwds)
- def get_unprivileged_tool(self, user: model.User, tool_uuid: Union[UUID, str]) -> Optional["Tool"]:
+ def get_unprivileged_tool(self, user: model.User, tool_uuid: UUID | str) -> Optional["Tool"]:
dynamic_tool = self.app.dynamic_tool_manager.get_unprivileged_tool_by_uuid(user, tool_uuid)
return self.dynamic_tool_to_tool(dynamic_tool)
- def get_unprivileged_tool_or_none(self, user: model.User, tool_uuid: Union[UUID, str]) -> Optional["Tool"]:
+ def get_unprivileged_tool_or_none(self, user: model.User, tool_uuid: UUID | str) -> Optional["Tool"]:
try:
return self.get_unprivileged_tool(user, tool_uuid=tool_uuid)
except exceptions.InsufficientPermissionsException:
@@ -667,8 +666,8 @@ class ToolBox(AbstractToolBox):
job: model.Job,
exact=True,
check_access=True,
- user: Optional[model.User] = None,
- tool_version: Optional[str] = None,
+ user: model.User | None = None,
+ tool_version: str | None = None,
) -> Optional["Tool"]:
if (dynamic_tool := job.dynamic_tool) is not None:
if check_access and not dynamic_tool.public:
@@ -697,7 +696,7 @@ class ToolBox(AbstractToolBox):
}
def _get_tool_shed_repository(
- self, tool_shed: str, name: str, owner: str, installed_changeset_revision: Optional[str]
+ self, tool_shed: str, name: str, owner: str, installed_changeset_revision: str | None
) -> "ToolShedRepository":
# Abstract toolbox doesn't have a dependency on the database, so
# override _get_tool_shed_repository here to provide this information.
@@ -808,7 +807,7 @@ class JobContext(BaseJobContext):
input_dbkey,
object_store: "ObjectStore",
final_job_state: "JobState",
- max_discovered_files: Optional[int],
+ max_discovered_files: int | None,
flush_per_n_datasets=None,
):
self.tool = tool
@@ -858,7 +857,7 @@ class JobContext(BaseJobContext):
return self._job
@property
- def flush_per_n_datasets(self) -> Optional[int]:
+ def flush_per_n_datasets(self) -> int | None:
return self._flush_per_n_datasets
@property
@@ -995,15 +994,15 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
def __init__(
self,
- config_file: Optional[StrPath],
+ config_file: StrPath | None,
tool_source: ToolSource,
app: "UniverseApplication",
- guid: Optional[str] = None,
+ guid: str | None = None,
repository_id=None,
tool_shed_repository=None,
allow_code_files: bool = True,
dynamic: bool = False,
- tool_dir: Optional[StrPath] = None,
+ tool_dir: StrPath | None = None,
):
"""Load a tool from the config named by `config_file`"""
self.config_file = os.path.realpath(config_file) if config_file else None
@@ -1020,7 +1019,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
self.stdio_regexes: list = []
self.inputs_by_page: list[dict] = []
self.display_by_page: list = []
- self.action: Union[str, tuple[str, str]] = "/tool_runner/index"
+ self.action: str | tuple[str, str] = "/tool_runner/index"
self.target = "galaxy_main"
self.method = "post"
self.labels: list = []
@@ -1031,11 +1030,11 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
self.require_login = False
self.rerun = False
# This will be non-None for tools loaded from the database (DynamicTool objects).
- self.dynamic_tool: Optional[DynamicTool] = None
+ self.dynamic_tool: DynamicTool | None = None
# Primitives snapshotted from DynamicTool so allow_user_access never
# touches a possibly-detached ORM row.
- self.dynamic_tool_id: Optional[int] = None
- self.dynamic_tool_uuid: Optional[UUID] = None
+ self.dynamic_tool_id: int | None = None
+ self.dynamic_tool_uuid: UUID | None = None
self.is_unprivileged_tool: bool = False
self.dynamic_tool_active: bool = True
# Define a place to keep track of all input These
@@ -1046,38 +1045,38 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
# tool_data_table_conf.xml entries exist.
self.input_params: list[ToolParameter] = []
# Attributes of tools installed from Galaxy tool sheds.
- self.tool_shed: Optional[str] = None
- self.repository_name: Optional[str] = None
- self.repository_owner: Optional[str] = None
- self.changeset_revision: Optional[str] = None
- self.installed_changeset_revision: Optional[str] = None
- self.sharable_url: Optional[str] = None
+ self.tool_shed: str | None = None
+ self.repository_name: str | None = None
+ self.repository_owner: str | None = None
+ self.changeset_revision: str | None = None
+ self.installed_changeset_revision: str | None = None
+ self.sharable_url: str | None = None
self.npages = 0
# The tool.id value will be the value of guid, but we'll keep the
# guid attribute since it is useful to have.
self.guid = guid
- self.old_id: Optional[str] = None
- self.python_template_version: Optional[Version] = None
- self._lineage: Optional[ToolLineage] = None
+ self.old_id: str | None = None
+ self.python_template_version: Version | None = None
+ self._lineage: ToolLineage | None = None
self.dependencies: list = []
# populate toolshed repository info, if available
self.populate_tool_shed_info(tool_shed_repository)
# add tool resource parameters
self.populate_resource_parameters(tool_source)
- self.tool_errors: Optional[str] = None
+ self.tool_errors: str | None = None
# Parse XML element containing configuration
self.tool_source = tool_source
self.outputs: dict[str, ToolOutputBase] = {}
self.output_collections: dict[str, ToolOutputCollection] = {}
- self.command: Optional[str] = None
- self.base_command: Optional[list[str]] = None
- self.arguments: Optional[list[str]] = []
- self.shell_command: Optional[str] = None
- self.javascript_requirements: Optional[list[JavascriptRequirement]] = None
- self.credentials: Optional[list[CredentialsRequirement]] = None
+ self.command: str | None = None
+ self.base_command: list[str] | None = None
+ self.arguments: list[str] | None = []
+ self.shell_command: str | None = None
+ self.javascript_requirements: list[JavascriptRequirement] | None = None
+ self.credentials: list[CredentialsRequirement] | None = None
self._is_workflow_compatible = None
- self.__tests: Optional[str] = None
- self.parameters: Optional[list[ToolParameterT]] = None
+ self.__tests: str | None = None
+ self.parameters: list[ToolParameterT] | None = None
self.template_macro_params: dict = {}
self._macro_paths: list = []
self.ports: list = []
@@ -1234,7 +1233,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
)
return legacy_tool
- def __get_job_tool_configuration(self, job_params: Union[dict, None] = None) -> "JobToolConfiguration":
+ def __get_job_tool_configuration(self, job_params: dict | None = None) -> "JobToolConfiguration":
"""Generalized method for getting this tool's job configuration.
:type job_params: dict or None
@@ -1267,7 +1266,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
), f"Could not get a job tool configuration for Tool {self.id} with job_params {job_params}, this is a bug"
return rval
- def get_configured_job_handler(self) -> Union[str, None]:
+ def get_configured_job_handler(self) -> str | None:
"""Get the configured job handler for this `Tool`.
Unlike the former ``get_job_handler()`` method, this does not perform "preassignment" (random selection of
@@ -1277,13 +1276,13 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
"""
return self.__get_job_tool_configuration().handler
- def get_job_destination(self, job_params: Union[dict, None] = None) -> "JobDestination":
+ def get_job_destination(self, job_params: dict | None = None) -> "JobDestination":
"""
:returns: The destination definition and runner parameters.
"""
return self.app.job_config.get_destination(self.__get_job_tool_configuration(job_params=job_params).destination)
- def get_panel_section(self) -> Union[tuple[str, str], tuple[None, None]]:
+ def get_panel_section(self) -> tuple[str, str] | tuple[None, None]:
return self.app.toolbox.get_section_for_tool(self)
def allow_user_access(self, user, attempting_access: bool = True) -> bool:
@@ -1302,7 +1301,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
return False
return owned is not None
- def parse(self, tool_source: ToolSource, guid: Optional[str] = None, dynamic: bool = False) -> None:
+ def parse(self, tool_source: ToolSource, guid: str | None = None, dynamic: bool = False) -> None:
"""
Read tool configuration from the element `root` and fill in `self`.
"""
@@ -1589,7 +1588,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
self.uihints[key] = value
def __parse_config_files(self, tool_source: ToolSource):
- self.config_files: Sequence[Union[TemplateConfigFile, InputConfigFile, FileSourceConfigFile]] = []
+ self.config_files: Sequence[TemplateConfigFile | InputConfigFile | FileSourceConfigFile] = []
self.config_files.extend(tool_source.parse_input_configfiles())
self.config_files.extend(tool_source.parse_template_configfiles())
@@ -2002,14 +2001,14 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
return help_html
@property
- def biotools_reference(self) -> Optional[str]:
+ def biotools_reference(self) -> str | None:
"""Return a bio.tools ID if external reference to it is found.
If multiple bio.tools references are found, return just the first one.
"""
return biotools_reference(self.xrefs)
- def __get_help_with_images(self, help_content: Optional[HelpContent]) -> Optional[HelpContent]:
+ def __get_help_with_images(self, help_content: HelpContent | None) -> HelpContent | None:
if help_content and help_content.format == "restructuredtext":
help_text = help_content.content or ""
try:
@@ -2114,11 +2113,11 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
self,
request_context: WorkRequestContext,
tool_request_internal_state: RequestInternalDereferencedToolState,
- rerun_remap_job_id: Optional[int],
+ rerun_remap_job_id: int | None,
) -> tuple[
list[ToolStateJobInstancePopulatedT],
list[ParameterValidationErrorsT],
- Optional[MatchingCollections],
+ MatchingCollections | None,
list[JobInternalToolState],
]:
"""The tool request API+tasks version of expand_incoming.
@@ -2135,7 +2134,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
expanded_incomings: list[ToolStateJobInstanceExpansionT]
job_tool_states: list[ToolStateJobInstanceT]
- collection_info: Optional[MatchingCollections]
+ collection_info: MatchingCollections | None
expanded_incomings, job_tool_states, collection_info = expand_meta_parameters_async(
request_context.app, self, tool_request_internal_state
)
@@ -2176,15 +2175,15 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
) -> tuple[
list[ToolStateJobInstancePopulatedT],
list[ParameterValidationErrorsT],
- Optional[int],
- Optional[MatchingCollections],
+ int | None,
+ MatchingCollections | None,
]:
rerun_remap_job_id = _rerun_remap_job_id(request_context, incoming, self.id)
set_dataset_matcher_factory(request_context, self)
# Fixed set of input parameters may correspond to any number of jobs.
# Expand these out to individual parameters for given jobs (tool executions).
expanded_incomings: list[ToolStateJobInstanceExpansionT]
- collection_info: Optional[MatchingCollections]
+ collection_info: MatchingCollections | None
expanded_incomings, collection_info = expand_meta_parameters(
request_context, self, incoming, input_format=input_format
)
@@ -2210,8 +2209,8 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
def _ensure_expansion_is_valid(
self,
- expanded_incomings: Union[list[JobInternalToolState], list[ToolStateJobInstanceT]],
- rerun_remap_job_id: Optional[int],
+ expanded_incomings: list[JobInternalToolState] | list[ToolStateJobInstanceT],
+ rerun_remap_job_id: int | None,
) -> None:
"""If the request corresponds to multiple jobs but this doesn't work with request configuration - raise an error.
@@ -2303,8 +2302,8 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
trans,
use_cached_job: bool,
all_params: list[ToolStateJobInstancePopulatedT],
- ) -> dict[int, Optional[Job]]:
- completed_jobs: dict[int, Optional[Job]] = {}
+ ) -> dict[int, Job | None]:
+ completed_jobs: dict[int, Job | None] = {}
for i, param in enumerate(all_params):
if use_cached_job and trans.user:
tool_id = self.id
@@ -2328,11 +2327,11 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
request_context: WorkRequestContext,
tool_request: ToolRequest,
tool_state: RequestInternalDereferencedToolState,
- history: Optional[model.History] = None,
+ history: model.History | None = None,
use_cached_job: bool = DEFAULT_USE_CACHED_JOB,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- rerun_remap_job_id: Optional[int] = None,
- credentials_context: Optional[CredentialsContext] = None,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ rerun_remap_job_id: int | None = None,
+ credentials_context: CredentialsContext | None = None,
input_format: str = "legacy",
):
"""The tool request API+tasks version of handle_input."""
@@ -2342,9 +2341,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
self.handle_incoming_errors(all_errors)
mapping_params = MappingParameters(tool_request.request, all_params, tool_state, job_tool_states)
- completed_jobs: dict[int, Optional[model.Job]] = self.completed_jobs(
- request_context, use_cached_job, all_params
- )
+ completed_jobs: dict[int, model.Job | None] = self.completed_jobs(request_context, use_cached_job, all_params)
return execute_async(
request_context,
self,
@@ -2362,12 +2359,12 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
self,
trans,
incoming: ToolRequestT,
- history: Optional[History] = None,
+ history: History | None = None,
use_cached_job: bool = DEFAULT_USE_CACHED_JOB,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
input_format: InputFormatT = "legacy",
- tags: Optional[list[str]] = None,
+ tags: list[str] | None = None,
send_email_notification: bool = False,
):
"""
@@ -2387,7 +2384,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
mapping_params = MappingParameters(incoming, all_params, None, None)
if use_cached_job:
mapping_params.param_template["__use_cached_job__"] = use_cached_job
- completed_jobs: dict[int, Optional[Job]] = self.completed_jobs(trans, use_cached_job, all_params)
+ completed_jobs: dict[int, Job | None] = self.completed_jobs(trans, use_cached_job, all_params)
execution_tracker = execute_sync(
trans,
self,
@@ -2450,15 +2447,15 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
def handle_single_execution(
self,
trans,
- rerun_remap_job_id: Optional[int],
+ rerun_remap_job_id: int | None,
execution_slice: ExecutionSlice,
history: History,
execution_cache: ToolExecutionCache,
- completed_job: Optional[Job],
- collection_info: Optional[MatchingCollections],
- job_callback: Optional[JobCallbackT],
- preferred_object_store_id: Optional[str],
- credentials_context: Optional[CredentialsContext],
+ completed_job: Job | None,
+ collection_info: MatchingCollections | None,
+ job_callback: JobCallbackT | None,
+ preferred_object_store_id: str | None,
+ credentials_context: CredentialsContext | None,
flush_job: bool,
skip: bool,
):
@@ -2559,11 +2556,11 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
def execute(
self,
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- history: Optional[History] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ history: History | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
- completed_job: Optional[Job] = None,
+ completed_job: Job | None = None,
):
"""
Execute the tool using parameter values in `incoming`. This just
@@ -2587,17 +2584,17 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
def _execute(
self,
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- validated_parameters: Optional[JobInternalToolState] = None,
- history: Optional[History] = None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- execution_cache: Optional[ToolExecutionCache] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = None,
- completed_job: Optional[Job] = None,
- collection_info: Optional[MatchingCollections] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ validated_parameters: JobInternalToolState | None = None,
+ history: History | None = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ execution_cache: ToolExecutionCache | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = None,
+ completed_job: Job | None = None,
+ collection_info: MatchingCollections | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
skip: bool = False,
@@ -2806,7 +2803,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
def exec_before_job(self, app, inp_data: InpDataDictT, out_data: OutDataDictT, param_dict=None):
pass
- def exec_after_process(self, app, inp_data, out_data, param_dict, job, final_job_state: Optional[str] = None):
+ def exec_after_process(self, app, inp_data, out_data, param_dict, job, final_job_state: str | None = None):
pass
def job_failed(self, job_wrapper, message, exception=False):
@@ -3046,10 +3043,10 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
self,
trans,
kwd=None,
- job: Optional[Job] = None,
+ job: Job | None = None,
workflow_building_mode=False,
- history: Optional[History] = None,
- options_pagination: Optional[OptionsPaginationT] = None,
+ history: History | None = None,
+ options_pagination: OptionsPaginationT | None = None,
):
"""
Recursively creates a tool dictionary containing repeats, dynamic options and updated states.
@@ -3176,7 +3173,7 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
state_inputs,
group_inputs,
other_values=None,
- options_pagination: Optional[OptionsPaginationT] = None,
+ options_pagination: OptionsPaginationT | None = None,
):
"""
Populates the tool model consumed by the client form builder.
@@ -3198,13 +3195,13 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
assert history
# Create index for hdas.
- hda_source_dict: dict[Union[int, str], HistoryDatasetAssociation] = {}
+ hda_source_dict: dict[int | str, HistoryDatasetAssociation] = {}
for hda in history.datasets:
key = f"{hda.hid}_{hda.dataset.id}"
hda_source_dict[hda.dataset.id] = hda_source_dict[key] = hda
# Ditto for dataset collections.
- hdca_source_dict: dict[Union[int, str], HistoryDatasetCollectionAssociation] = {}
+ hdca_source_dict: dict[int | str, HistoryDatasetCollectionAssociation] = {}
for hdca in history.dataset_collections:
key = f"{hdca.hid}_{hdca.collection.id}"
hdca_source_dict[hdca.collection.id] = hdca_source_dict[key] = hdca
@@ -3214,10 +3211,9 @@ class Tool(UsesDictVisibleKeys, MaybeToolParameterBundle):
if isinstance(value, HistoryDatasetAssociation):
assert value.dataset is not None
id = value.dataset.id
- source: Union[
- dict[Union[int, str], HistoryDatasetAssociation],
- dict[Union[int, str], HistoryDatasetCollectionAssociation],
- ] = hda_source_dict
+ source: (
+ dict[int | str, HistoryDatasetAssociation] | dict[int | str, HistoryDatasetCollectionAssociation]
+ ) = hda_source_dict
elif isinstance(value, HistoryDatasetCollectionAssociation):
id = value.collection.id
source = hdca_source_dict
@@ -3392,7 +3388,7 @@ class ExpressionTool(Tool):
tool_type_local = True
EXPRESSION_INPUTS_NAME = "_expression_inputs_.json"
- def parse(self, tool_source: ToolSource, guid: Optional[str] = None, dynamic: bool = False) -> None:
+ def parse(self, tool_source: ToolSource, guid: str | None = None, dynamic: bool = False) -> None:
super().parse(tool_source, guid, dynamic)
if self.profile < 19.05:
# Expression tools were introduced in 19.05 and we don't want crazy stuff like failing on stderr
@@ -3922,8 +3918,9 @@ class UnzipCollectionTool(DatabaseOperationTool):
assert collection.collection_type == "paired"
forward_o, reverse_o = collection.dataset_instances
- forward, reverse = forward_o.copy(copy_tags=forward_o.tags, flush=False), reverse_o.copy(
- copy_tags=reverse_o.tags, flush=False
+ forward, reverse = (
+ forward_o.copy(copy_tags=forward_o.tags, flush=False),
+ reverse_o.copy(copy_tags=reverse_o.tags, flush=False),
)
self._add_datasets_to_history(history, [forward, reverse])
@@ -3940,8 +3937,9 @@ class ZipCollectionTool(DatabaseOperationTool):
forward_o = incoming["input_forward"]
reverse_o = incoming["input_reverse"]
- forward, reverse = forward_o.copy(copy_tags=forward_o.tags, flush=False), reverse_o.copy(
- copy_tags=reverse_o.tags, flush=False
+ forward, reverse = (
+ forward_o.copy(copy_tags=forward_o.tags, flush=False),
+ reverse_o.copy(copy_tags=reverse_o.tags, flush=False),
)
new_elements = {}
new_elements["forward"] = forward
@@ -5059,7 +5057,7 @@ tool_types = {tool_class.tool_type: tool_class for tool_class in TOOL_CLASSES}
# ---- Utility classes to be factored out -----------------------------------
-def _rerun_remap_job_id(trans, incoming, tool_id: Optional[str]) -> Optional[int]:
+def _rerun_remap_job_id(trans, incoming, tool_id: str | None) -> int | None:
rerun_remap_job_id = None
if "rerun_remap_job_id" in incoming:
try:
diff --git a/lib/galaxy/tools/actions/__init__.py b/lib/galaxy/tools/actions/__init__.py
index 3088a070043..b9c90fd504c 100644
--- a/lib/galaxy/tools/actions/__init__.py
+++ b/lib/galaxy/tools/actions/__init__.py
@@ -10,9 +10,7 @@ from collections.abc import (
from typing import (
Any,
cast,
- Optional,
TYPE_CHECKING,
- Union,
)
from packaging.version import Version
@@ -86,7 +84,7 @@ log = logging.getLogger(__name__)
OutputDatasetsT = dict[str, "DatasetInstance"]
-ToolActionExecuteResult = Union[tuple[Job, OutputDatasetsT, Optional[History]], tuple[Job, OutputDatasetsT]]
+ToolActionExecuteResult = tuple[Job, OutputDatasetsT, History | None] | tuple[Job, OutputDatasetsT]
class ToolAction:
@@ -100,17 +98,17 @@ class ToolAction:
self,
tool: "Tool",
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- history: Optional[History] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ history: History | None = None,
job_params=None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- execution_cache: Optional[ToolExecutionCache] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = DEFAULT_DATASET_COLLECTION_ELEMENTS,
- completed_job: Optional[Job] = None,
- collection_info: Optional[MatchingCollections] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ execution_cache: ToolExecutionCache | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = DEFAULT_DATASET_COLLECTION_ELEMENTS,
+ completed_job: Job | None = None,
+ collection_info: MatchingCollections | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
skip: bool = False,
@@ -284,7 +282,7 @@ class DefaultToolAction(ToolAction):
child_collection = False
if isinstance(value, CollectionAdapter):
# collection was created for this execution, use it as is
- collection: Union[CollectionAdapter, DatasetCollection] = value
+ collection: CollectionAdapter | DatasetCollection = value
elif hasattr(value, "child_collection"):
# if we are mapping a collection over a tool, so value is a DCE and
# we only require the child_collection
@@ -445,17 +443,17 @@ class DefaultToolAction(ToolAction):
self,
tool: "Tool",
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- history: Optional[History] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ history: History | None = None,
job_params=None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- execution_cache: Optional[ToolExecutionCache] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = DEFAULT_DATASET_COLLECTION_ELEMENTS,
- completed_job: Optional[Job] = None,
- collection_info: Optional[MatchingCollections] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ execution_cache: ToolExecutionCache | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = DEFAULT_DATASET_COLLECTION_ELEMENTS,
+ completed_job: Job | None = None,
+ collection_info: MatchingCollections | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
skip: bool = False,
@@ -660,7 +658,7 @@ class DefaultToolAction(ToolAction):
# Output collection is mapped over and has already been copied from original job
continue
collections_manager = app.dataset_collection_manager
- element_identifiers: list[dict[str, Union[str, list[dict[str, Union[str, list[Any]]]]]]] = []
+ element_identifiers: list[dict[str, str | list[dict[str, str | list[Any]]]]] = []
# mypy doesn't yet support recursive type definitions
known_outputs = output.known_outputs(input_collections, collections_manager.type_registry)
# Just to echo TODO elsewhere - this should be restructured to allow
@@ -695,7 +693,7 @@ class DefaultToolAction(ToolAction):
list[
dict[
str,
- Union[str, list[dict[str, Union[str, list[Any]]]]],
+ str | list[dict[str, str | list[Any]]],
]
],
current_element_identifiers[index]["element_identifiers"],
@@ -812,7 +810,7 @@ class DefaultToolAction(ToolAction):
def _remap_job_on_rerun(
self,
trans: ProvidesHistoryContext,
- galaxy_session: Optional[model.GalaxySession],
+ galaxy_session: model.GalaxySession | None,
rerun_remap_job_id: int,
current_job: Job,
out_data,
@@ -925,7 +923,7 @@ class DefaultToolAction(ToolAction):
trans,
tool: "Tool",
incoming: "ToolStateJobInstancePopulatedT",
- input_datasets: Optional[LegacyUnprefixedDict] = None,
+ input_datasets: LegacyUnprefixedDict | None = None,
) -> WrappedParameters:
wrapped_params = WrappedParameters(trans, tool, incoming, input_datasets=input_datasets)
return wrapped_params
@@ -952,8 +950,8 @@ class DefaultToolAction(ToolAction):
return on_text_for_dataset_and_collections(dataset_hids=input_hids, collection_hids=collection_hids)
def _new_job_for_session(
- self, trans, tool: "Tool", history: Optional[History]
- ) -> tuple[Job, Optional[model.GalaxySession]]:
+ self, trans, tool: "Tool", history: History | None
+ ) -> tuple[Job, model.GalaxySession | None]:
job = Job()
job.galaxy_version = trans.app.config.version_major
galaxy_session = None
@@ -980,7 +978,7 @@ class DefaultToolAction(ToolAction):
return job, galaxy_session
def _handle_credentials_context(
- self, sa_session: galaxy_scoped_session, job: Job, credentials_context: Optional[CredentialsContext]
+ self, sa_session: galaxy_scoped_session, job: Job, credentials_context: CredentialsContext | None
) -> None:
if credentials_context is None:
return
diff --git a/lib/galaxy/tools/actions/data_manager.py b/lib/galaxy/tools/actions/data_manager.py
index be1e6badc04..c15b3815630 100644
--- a/lib/galaxy/tools/actions/data_manager.py
+++ b/lib/galaxy/tools/actions/data_manager.py
@@ -1,5 +1,4 @@
import logging
-from typing import Optional
from galaxy.model import (
DataManagerJobAssociation,
@@ -34,17 +33,17 @@ class DataManagerToolAction(DefaultToolAction):
self,
tool,
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- history: Optional[History] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ history: History | None = None,
job_params=None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- execution_cache: Optional[ToolExecutionCache] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = DEFAULT_DATASET_COLLECTION_ELEMENTS,
- completed_job: Optional[Job] = None,
- collection_info: Optional[MatchingCollections] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ execution_cache: ToolExecutionCache | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = DEFAULT_DATASET_COLLECTION_ELEMENTS,
+ completed_job: Job | None = None,
+ collection_info: MatchingCollections | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
skip: bool = False,
diff --git a/lib/galaxy/tools/actions/history_imp_exp.py b/lib/galaxy/tools/actions/history_imp_exp.py
index 88811c86b25..bfc0dc90794 100644
--- a/lib/galaxy/tools/actions/history_imp_exp.py
+++ b/lib/galaxy/tools/actions/history_imp_exp.py
@@ -2,7 +2,6 @@ import datetime
import logging
import os
import tempfile
-from typing import Optional
from galaxy.job_execution.setup import create_working_directory_for_job
from galaxy.model import (
@@ -46,17 +45,17 @@ class ImportHistoryToolAction(ToolAction):
self,
tool,
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- history: Optional[History] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ history: History | None = None,
job_params=None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- execution_cache: Optional[ToolExecutionCache] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = DEFAULT_DATASET_COLLECTION_ELEMENTS,
- completed_job: Optional[Job] = None,
- collection_info: Optional[MatchingCollections] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ execution_cache: ToolExecutionCache | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = DEFAULT_DATASET_COLLECTION_ELEMENTS,
+ completed_job: Job | None = None,
+ collection_info: MatchingCollections | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
skip: bool = False,
@@ -123,17 +122,17 @@ class ExportHistoryToolAction(ToolAction):
self,
tool,
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- history: Optional[History] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ history: History | None = None,
job_params=None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- execution_cache: Optional[ToolExecutionCache] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = DEFAULT_DATASET_COLLECTION_ELEMENTS,
- completed_job: Optional[Job] = None,
- collection_info: Optional[MatchingCollections] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ execution_cache: ToolExecutionCache | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = DEFAULT_DATASET_COLLECTION_ELEMENTS,
+ completed_job: Job | None = None,
+ collection_info: MatchingCollections | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
skip: bool = False,
diff --git a/lib/galaxy/tools/actions/metadata.py b/lib/galaxy/tools/actions/metadata.py
index 0ff05164aad..8c9ff587340 100644
--- a/lib/galaxy/tools/actions/metadata.py
+++ b/lib/galaxy/tools/actions/metadata.py
@@ -2,7 +2,6 @@ import logging
import os
from typing import (
Any,
- Optional,
)
from galaxy.job_execution.datasets import DatasetPath
@@ -45,17 +44,17 @@ class SetMetadataToolAction(ToolAction):
self,
tool,
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- history: Optional[History] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ history: History | None = None,
job_params=None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- execution_cache: Optional[ToolExecutionCache] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = DEFAULT_DATASET_COLLECTION_ELEMENTS,
- completed_job: Optional[Job] = None,
- collection_info: Optional[MatchingCollections] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ execution_cache: ToolExecutionCache | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = DEFAULT_DATASET_COLLECTION_ELEMENTS,
+ completed_job: Job | None = None,
+ collection_info: MatchingCollections | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
skip: bool = False,
@@ -80,10 +79,10 @@ class SetMetadataToolAction(ToolAction):
self,
tool,
trans,
- incoming: Optional[dict[str, Any]],
+ incoming: dict[str, Any] | None,
overwrite: bool = True,
- history: Optional[History] = None,
- job_params: Optional[dict[str, Any]] = None,
+ history: History | None = None,
+ job_params: dict[str, Any] | None = None,
):
trans.check_user_activation()
session = trans.get_galaxy_session()
@@ -106,13 +105,13 @@ class SetMetadataToolAction(ToolAction):
self,
tool,
app,
- session_id: Optional[int],
- history_id: Optional[int],
- user: Optional[User] = None,
- incoming: Optional[dict[str, Any]] = None,
+ session_id: int | None,
+ history_id: int | None,
+ user: User | None = None,
+ incoming: dict[str, Any] | None = None,
overwrite: bool = True,
- history: Optional[History] = None,
- job_params: Optional[dict[str, Any]] = None,
+ history: History | None = None,
+ job_params: dict[str, Any] | None = None,
):
"""
Execute using application.
diff --git a/lib/galaxy/tools/actions/model_operations.py b/lib/galaxy/tools/actions/model_operations.py
index f38ea4c3d45..a640547228c 100644
--- a/lib/galaxy/tools/actions/model_operations.py
+++ b/lib/galaxy/tools/actions/model_operations.py
@@ -1,6 +1,5 @@
import logging
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -57,17 +56,17 @@ class ModelOperationToolAction(DefaultToolAction):
self,
tool: "Tool",
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- history: Optional[History] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ history: History | None = None,
job_params=None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- execution_cache: Optional[ToolExecutionCache] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = DEFAULT_DATASET_COLLECTION_ELEMENTS,
- completed_job: Optional[Job] = None,
- collection_info: Optional[MatchingCollections] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ execution_cache: ToolExecutionCache | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = DEFAULT_DATASET_COLLECTION_ELEMENTS,
+ completed_job: Job | None = None,
+ collection_info: MatchingCollections | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
skip: bool = False,
diff --git a/lib/galaxy/tools/actions/upload.py b/lib/galaxy/tools/actions/upload.py
index 9e5973f8117..d5df6a95d91 100644
--- a/lib/galaxy/tools/actions/upload.py
+++ b/lib/galaxy/tools/actions/upload.py
@@ -1,7 +1,6 @@
import json
import logging
import os
-from typing import Optional
from galaxy.exceptions import RequestParameterMissingException
from galaxy.job_execution.output_collect import copy_collection_metadata_from_target_dict
@@ -41,17 +40,17 @@ class BaseUploadToolAction(ToolAction):
self,
tool,
trans,
- incoming: Optional[ToolStateJobInstancePopulatedT] = None,
- history: Optional[History] = None,
+ incoming: ToolStateJobInstancePopulatedT | None = None,
+ history: History | None = None,
job_params=None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- execution_cache: Optional[ToolExecutionCache] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = DEFAULT_DATASET_COLLECTION_ELEMENTS,
- completed_job: Optional[Job] = None,
- collection_info: Optional[MatchingCollections] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ execution_cache: ToolExecutionCache | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = DEFAULT_DATASET_COLLECTION_ELEMENTS,
+ completed_job: Job | None = None,
+ collection_info: MatchingCollections | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
set_output_hid: bool = DEFAULT_SET_OUTPUT_HID,
flush_job: bool = True,
skip: bool = False,
diff --git a/lib/galaxy/tools/actions/upload_common.py b/lib/galaxy/tools/actions/upload_common.py
index 835b0b8313c..e24f9cb6627 100644
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -7,9 +7,6 @@ from json import (
dump,
dumps,
)
-from typing import (
- Optional,
-)
from sqlalchemy import select
from sqlalchemy.orm import joinedload
@@ -81,16 +78,16 @@ def persist_uploads(params, trans):
@dataclass
class LibraryParams:
roles: list[Role]
- tags: Optional[list[str]]
- template: Optional[FormDefinition]
+ tags: list[str] | None
+ template: FormDefinition | None
template_field_contents: dict[str, str]
folder: LibraryFolder
message: str
- replace_dataset: Optional[LibraryDataset]
+ replace_dataset: LibraryDataset | None
def handle_library_params(
- trans, params, folder_id: int, replace_dataset: Optional[LibraryDataset] = None
+ trans, params, folder_id: int, replace_dataset: LibraryDataset | None = None
) -> LibraryParams:
session = trans.sa_session
# FIXME: the received params has already been parsed by util.Params() by the time it reaches here,
@@ -103,7 +100,7 @@ def handle_library_params(
folder = session.get(LibraryFolder, folder_id)
# We are inheriting the folder's info_association, so we may have received inherited contents or we may have redirected
# here after the user entered template contents ( due to errors ).
- template: Optional[FormDefinition] = None
+ template: FormDefinition | None = None
if template_id not in [None, "None"]:
template = session.get(FormDefinition, template_id)
if template and template.fields:
diff --git a/lib/galaxy/tools/cache.py b/lib/galaxy/tools/cache.py
index b950a95b315..dcc427f4407 100644
--- a/lib/galaxy/tools/cache.py
+++ b/lib/galaxy/tools/cache.py
@@ -2,7 +2,6 @@ import logging
import os
from threading import Lock
from typing import (
- Optional,
TYPE_CHECKING,
Union,
)
@@ -142,15 +141,15 @@ class ToolCache:
class ToolHash:
- def __init__(self, path: "StrPath", modtime: Optional[float] = None, lazy_hash: bool = False) -> None:
+ def __init__(self, path: "StrPath", modtime: float | None = None, lazy_hash: bool = False) -> None:
self.path = path
self.modtime = modtime or os.path.getmtime(path)
- self._tool_hash: Optional[str] = None
+ self._tool_hash: str | None = None
if not lazy_hash:
self.hash # noqa: B018
@property
- def hash(self) -> Union[str, None]:
+ def hash(self) -> str | None:
if self._tool_hash is None:
self._tool_hash = md5_hash_file(self.path)
return self._tool_hash
diff --git a/lib/galaxy/tools/data_fetch.py b/lib/galaxy/tools/data_fetch.py
index 09fcb7c5b7a..c8c186699b5 100644
--- a/lib/galaxy/tools/data_fetch.py
+++ b/lib/galaxy/tools/data_fetch.py
@@ -8,7 +8,6 @@ import tempfile
from io import StringIO
from typing import (
Any,
- Optional,
)
import bdbag.bdbag_api
@@ -60,7 +59,7 @@ def do_fetch(
request_path: str,
working_directory: str,
registry: Registry,
- file_sources_dict: Optional[dict] = None,
+ file_sources_dict: dict | None = None,
):
assert os.path.exists(request_path)
with open(request_path) as f:
@@ -279,7 +278,7 @@ def _fetch_target(upload_config: "UploadConfig", target: dict[str, Any]):
link_data_only, link_data_only_explicit = _link_data_only(item)
name: str
- path: Optional[str]
+ path: str | None
default_in_place = False
if not deferred:
name, path, is_link = _has_src_to_path(
@@ -328,7 +327,7 @@ def _fetch_target(upload_config: "UploadConfig", target: dict[str, Any]):
requested_transform.append({"action": "to_posix_lines"})
source_dict["requested_transform"] = requested_transform
effective_state = "ok"
- stdout: Optional[str] = None
+ stdout: str | None = None
if not deferred and not error_message:
in_place = item.get("in_place", default_in_place)
purge_source = item.get("purge_source", True)
@@ -515,7 +514,7 @@ def _directory_to_items(directory):
return items
-def _has_src_to_name(item) -> Optional[str]:
+def _has_src_to_name(item) -> str | None:
# Logic should broadly match logic of _has_src_to_path but not resolve the item
# into a path.
name = item.get("name")
@@ -559,7 +558,7 @@ def _has_src_to_path(
return name, path, is_link
headers = item.get("headers")
- file_source_options: Optional[FilesSourceOptions] = None
+ file_source_options: FilesSourceOptions | None = None
if headers:
extra_props = PartialFilesSourceProperties(**{"http_headers": headers})
file_source_options = FilesSourceOptions(extra_props=extra_props)
@@ -633,7 +632,7 @@ class UploadConfig:
registry: Registry,
working_directory: str,
allow_failed_collections: bool,
- file_sources_dict: Optional[dict] = None,
+ file_sources_dict: dict | None = None,
):
self.registry = registry
self.working_directory = working_directory
diff --git a/lib/galaxy/tools/data_manager/manager.py b/lib/galaxy/tools/data_manager/manager.py
index b7f7fb6da47..f885736be43 100644
--- a/lib/galaxy/tools/data_manager/manager.py
+++ b/lib/galaxy/tools/data_manager/manager.py
@@ -3,7 +3,6 @@ import logging
import os
from typing import (
Optional,
- Union,
)
from typing_extensions import Protocol
@@ -29,11 +28,11 @@ class DataManagers(DataManagersInterface):
managed_data_tables: dict[str, "DataManager"]
__reload_count: int
- def __init__(self, app: StructuredApp, xml_filename=None, reload_count: Optional[int] = None):
+ def __init__(self, app: StructuredApp, xml_filename=None, reload_count: int | None = None):
self.app = app
self.data_managers = {}
self.managed_data_tables = {}
- self.tool_path: Optional[str] = None
+ self.tool_path: str | None = None
self.__reload_count = reload_count or 0
self.filename = xml_filename or self.app.config.data_manager_config_file
for filename in util.listify(self.filename):
@@ -108,7 +107,7 @@ class DataManagers(DataManagersInterface):
def get_manager(self, *args, **kwds):
return self.data_managers.get(*args, **kwds)
- def remove_manager(self, manager_ids: Union[str, list[str]]) -> None:
+ def remove_manager(self, manager_ids: str | list[str]) -> None:
if not isinstance(manager_ids, list):
manager_ids = [manager_ids]
for manager_id in manager_ids:
@@ -139,22 +138,22 @@ class DataManager:
GUID_TYPE = "data_manager"
DEFAULT_VERSION = "0.0.1"
- tool: Optional[Tool]
+ tool: Tool | None
- def __init__(self, data_managers: DataManagers, elem: Optional[Element] = None, tool_path: Optional[str] = None):
+ def __init__(self, data_managers: DataManagers, elem: Element | None = None, tool_path: str | None = None):
self.data_managers = data_managers
- self.declared_id: Optional[str] = None
- self.name: Optional[str] = None
- self.description: Optional[str] = None
+ self.declared_id: str | None = None
+ self.name: str | None = None
+ self.description: str | None = None
self.version = self.DEFAULT_VERSION
- self.guid: Optional[str] = None
+ self.guid: str | None = None
self.tool = None
- self.tool_shed_repository_info: Optional[RepoInfo] = None
+ self.tool_shed_repository_info: RepoInfo | None = None
self.undeclared_tables = False
if elem is not None:
self._load_from_element(elem, tool_path or self.data_managers.tool_path)
- def _load_from_element(self, elem: Element, tool_path: Optional[str]) -> None:
+ def _load_from_element(self, elem: Element, tool_path: str | None) -> None:
assert (
elem.tag == "data_manager"
), f'A data manager configuration must have a "data_manager" tag as the root. "{elem.tag}" is present'
@@ -261,11 +260,11 @@ class DataManager:
)
@property
- def repo_info(self) -> Optional[RepoInfo]:
+ def repo_info(self) -> RepoInfo | None:
return self.tool_shed_repository_info
# legacy stuff because tool shed code calls this...
# data manager manual integration test provides coverage
- def get_tool_shed_repository_info_dict(self) -> Optional[dict]:
+ def get_tool_shed_repository_info_dict(self) -> dict | None:
repo_info = self.repo_info
return repo_info.model_dump(mode="json") if repo_info else None
diff --git a/lib/galaxy/tools/evaluation.py b/lib/galaxy/tools/evaluation.py
index f7c6f9171d3..c64230843e1 100644
--- a/lib/galaxy/tools/evaluation.py
+++ b/lib/galaxy/tools/evaluation.py
@@ -10,9 +10,7 @@ from datetime import datetime
from typing import (
Any,
Literal,
- Optional,
TYPE_CHECKING,
- Union,
)
from packaging.version import Version
@@ -117,15 +115,14 @@ global_tool_errors = ToolErrorLog()
class ToolTemplatingException(Exception):
-
- def __init__(self, *args: object, tool_id: Optional[str], tool_version: str, is_latest: bool) -> None:
+ def __init__(self, *args: object, tool_id: str | None, tool_version: str, is_latest: bool) -> None:
super().__init__(*args)
self.tool_id = tool_id
self.tool_version = tool_version
self.is_latest = is_latest
-def global_tool_logs(func, config_file: Optional[StrPath], action_str: str, tool: "Tool"):
+def global_tool_logs(func, config_file: StrPath | None, action_str: str, tool: "Tool"):
try:
return func()
except Exception as e:
@@ -158,13 +155,13 @@ class ToolEvaluator:
self.param_dict: dict[str, Any] = {}
self.extra_filenames: list[str] = []
self.environment_variables: list[dict[str, str]] = []
- self.version_command_line: Optional[str] = None
- self.command_line: Optional[str] = None
+ self.version_command_line: str | None = None
+ self.command_line: str | None = None
self.interactivetools: list[dict[str, Any]] = []
self.consumes_names = False
self.use_cached_job = False
- def set_compute_environment(self, compute_environment: ComputeEnvironment, get_special: Optional[Callable] = None):
+ def set_compute_environment(self, compute_environment: ComputeEnvironment, get_special: Callable | None = None):
"""
Setup the compute environment and established the outline of the param_dict
for evaluating command and config cheetah templates.
@@ -218,7 +215,7 @@ class ToolEvaluator:
self.execute_tool_hooks(inp_data=inp_data, out_data=out_data, incoming=incoming)
else:
- tool_state: Optional[JobInternalToolState] = None
+ tool_state: JobInternalToolState | None = None
if job.tool_state:
tool_state = JobInternalToolState(job.tool_state)
self.param_dict = self.build_param_dict(
@@ -244,7 +241,7 @@ class ToolEvaluator:
input_datasets: InpDataDictT,
output_datasets: OutDataDictT,
output_collections: OutCollectionsDictT,
- validated_tool_state: Optional[JobInternalToolState] = None,
+ validated_tool_state: JobInternalToolState | None = None,
):
"""
Build the dictionary of parameters for substituting into the command
@@ -323,9 +320,7 @@ class ToolEvaluator:
undeferred_objects[key] = undeferred
elif isinstance(value, list):
undeferred_list: list[
- Union[
- model.DatasetInstance, model.HistoryDatasetCollectionAssociation, model.DatasetCollectionElement
- ]
+ model.DatasetInstance | model.HistoryDatasetCollectionAssociation | model.DatasetCollectionElement
] = []
for potentially_deferred in value:
if isinstance(potentially_deferred, model.DatasetInstance):
@@ -354,7 +349,7 @@ class ToolEvaluator:
def _eval_format_source(
self,
job: model.Job,
- inp_data: dict[str, Optional[model.DatasetInstance]],
+ inp_data: dict[str, model.DatasetInstance | None],
out_data: dict[str, model.DatasetInstance],
):
for output_name, output in out_data.items():
@@ -371,7 +366,7 @@ class ToolEvaluator:
def _replaced_deferred_objects(
self,
- inp_data: dict[str, Optional[model.DatasetInstance]],
+ inp_data: dict[str, model.DatasetInstance | None],
incoming: dict,
materalized_objects: dict[str, DeferrableObjectsT],
):
@@ -825,7 +820,7 @@ class ToolEvaluator:
environment_variable = environment_variable_def.copy()
environment_variable_template = environment_variable_def["template"]
inject = environment_variable_def.get("inject")
- template_type: Optional[Literal["cheetah"]] = None
+ template_type: Literal["cheetah"] | None = None
if inject == "api_key":
if self._user and isinstance(self.app, BasicSharedApp):
from galaxy.managers import api_keys
@@ -915,7 +910,7 @@ class ToolEvaluator:
else:
return None
- def _build_config_file_text(self, config_file: Union[TemplateConfigFile, InputConfigFile, FileSourceConfigFile]):
+ def _build_config_file_text(self, config_file: TemplateConfigFile | InputConfigFile | FileSourceConfigFile):
if isinstance(config_file, (XmlTemplateConfigFile, YamlTemplateConfigFile)):
return config_file.content, config_file.eval_engine
@@ -942,7 +937,7 @@ class ToolEvaluator:
config_filename,
content,
context,
- template_type: Optional[Literal["cheetah", "ecmascript"]] = None,
+ template_type: Literal["cheetah", "ecmascript"] | None = None,
strip=False,
):
parent_dir = os.path.dirname(config_filename)
@@ -1036,7 +1031,6 @@ class PartialToolEvaluator(ToolEvaluator):
class UserToolEvaluator(ToolEvaluator):
-
param_dict_style = "json"
def _build_config_files(self):
@@ -1077,7 +1071,7 @@ class UserToolEvaluator(ToolEvaluator):
input_datasets: InpDataDictT,
output_datasets: OutDataDictT,
output_collections: OutCollectionsDictT,
- validated_tool_state: Optional[JobInternalToolState] = None,
+ validated_tool_state: JobInternalToolState | None = None,
):
"""
Build the dictionary of parameters for substituting into the command
diff --git a/lib/galaxy/tools/execute.py b/lib/galaxy/tools/execute.py
index d3c06140522..38f4e3caaa2 100644
--- a/lib/galaxy/tools/execute.py
+++ b/lib/galaxy/tools/execute.py
@@ -15,9 +15,7 @@ from collections.abc import (
from typing import (
Any,
NamedTuple,
- Optional,
TypeAlias,
- Union,
)
from boltons.iterutils import remap
@@ -66,15 +64,15 @@ SINGLE_EXECUTION_SUCCESS_MESSAGE = "Tool ${tool_id} created job ${job_id}"
BATCH_EXECUTION_MESSAGE = "Created ${job_count} job(s) for tool ${tool_id} request"
-CompletedJobsT = dict[int, Optional[model.Job]]
+CompletedJobsT = dict[int, model.Job | None]
JobCallbackT: TypeAlias = Callable
WorkflowResourceParametersT = dict[str, Any]
DatasetCollectionElementsSliceT = dict[str, model.DatasetCollectionElement]
DEFAULT_USE_CACHED_JOB = False
-DEFAULT_PREFERRED_OBJECT_STORE_ID: Optional[str] = None
-DEFAULT_RERUN_REMAP_JOB_ID: Optional[int] = None
-DEFAULT_JOB_CALLBACK: Optional[JobCallbackT] = None
-DEFAULT_DATASET_COLLECTION_ELEMENTS: Optional[DatasetCollectionElementsSliceT] = None
+DEFAULT_PREFERRED_OBJECT_STORE_ID: str | None = None
+DEFAULT_RERUN_REMAP_JOB_ID: int | None = None
+DEFAULT_JOB_CALLBACK: JobCallbackT | None = None
+DEFAULT_DATASET_COLLECTION_ELEMENTS: DatasetCollectionElementsSliceT | None = None
DEFAULT_SET_OUTPUT_HID: bool = True
@@ -90,9 +88,9 @@ class MappingParameters(NamedTuple):
param_combinations: list[ToolStateJobInstancePopulatedT]
# schema driven parameters
# model validated tool request - might correspond to multiple jobs
- validated_param_template: Optional[RequestInternalDereferencedToolState] = None
+ validated_param_template: RequestInternalDereferencedToolState | None = None
# validated job parameters for individual jobs
- validated_param_combinations: Optional[list[JobInternalToolState]] = None
+ validated_param_combinations: list[JobInternalToolState] | None = None
def ensure_validated(self):
assert self.validated_param_template is not None
@@ -142,7 +140,7 @@ def _resolve_collection_ref(
ref: dict[str, Any],
trans: WorkRequestContext,
raw_fallback: Any,
-) -> Union[model.HistoryDatasetCollectionAssociation, model.DatasetCollectionElement, Any]:
+) -> model.HistoryDatasetCollectionAssociation | model.DatasetCollectionElement | Any:
src = ref.get("src")
rid = ref.get("id")
if rid is None or src not in ("hdca", "dce"):
@@ -170,16 +168,16 @@ def execute_async(
mapping_params: MappingParameters,
history: model.History,
tool_request: ToolRequest,
- completed_jobs: Optional[CompletedJobsT] = None,
- rerun_remap_job_id: Optional[int] = None,
- preferred_object_store_id: Optional[str] = None,
- credentials_context: Optional[CredentialsContext] = None,
- collection_info: Optional[MatchingCollections] = None,
- workflow_invocation_uuid: Optional[str] = None,
- invocation_step: Optional[model.WorkflowInvocationStep] = None,
- max_num_jobs: Optional[int] = None,
- job_callback: Optional[Callable] = None,
- workflow_resource_parameters: Optional[dict[str, Any]] = None,
+ completed_jobs: CompletedJobsT | None = None,
+ rerun_remap_job_id: int | None = None,
+ preferred_object_store_id: str | None = None,
+ credentials_context: CredentialsContext | None = None,
+ collection_info: MatchingCollections | None = None,
+ workflow_invocation_uuid: str | None = None,
+ invocation_step: model.WorkflowInvocationStep | None = None,
+ max_num_jobs: int | None = None,
+ job_callback: Callable | None = None,
+ workflow_resource_parameters: dict[str, Any] | None = None,
validate_outputs: bool = False,
) -> "ExecutionTracker":
"""The tool request/async version of execute."""
@@ -210,17 +208,17 @@ def execute(
tool: "Tool",
mapping_params: MappingParameters,
history: model.History,
- tool_request: Optional[ToolRequest] = None,
- rerun_remap_job_id: Optional[int] = DEFAULT_RERUN_REMAP_JOB_ID,
- preferred_object_store_id: Optional[str] = DEFAULT_PREFERRED_OBJECT_STORE_ID,
- credentials_context: Optional[CredentialsContext] = None,
- collection_info: Optional[MatchingCollections] = None,
- workflow_invocation_uuid: Optional[str] = None,
- invocation_step: Optional[model.WorkflowInvocationStep] = None,
- max_num_jobs: Optional[int] = None,
- job_callback: Optional[JobCallbackT] = DEFAULT_JOB_CALLBACK,
- completed_jobs: Optional[CompletedJobsT] = None,
- workflow_resource_parameters: Optional[WorkflowResourceParametersT] = None,
+ tool_request: ToolRequest | None = None,
+ rerun_remap_job_id: int | None = DEFAULT_RERUN_REMAP_JOB_ID,
+ preferred_object_store_id: str | None = DEFAULT_PREFERRED_OBJECT_STORE_ID,
+ credentials_context: CredentialsContext | None = None,
+ collection_info: MatchingCollections | None = None,
+ workflow_invocation_uuid: str | None = None,
+ invocation_step: model.WorkflowInvocationStep | None = None,
+ max_num_jobs: int | None = None,
+ job_callback: JobCallbackT | None = DEFAULT_JOB_CALLBACK,
+ completed_jobs: CompletedJobsT | None = None,
+ workflow_resource_parameters: WorkflowResourceParametersT | None = None,
validate_outputs: bool = False,
) -> "ExecutionTracker":
"""
@@ -253,17 +251,17 @@ def _execute(
tool: "Tool",
mapping_params: MappingParameters,
history: model.History,
- tool_request: Optional[ToolRequest],
- rerun_remap_job_id: Optional[int],
- preferred_object_store_id: Optional[str],
- credentials_context: Optional[CredentialsContext],
- collection_info: Optional[MatchingCollections],
- workflow_invocation_uuid: Optional[str],
- invocation_step: Optional[model.WorkflowInvocationStep],
- max_num_jobs: Optional[int],
- job_callback: Optional[Callable],
- completed_jobs: dict[int, Optional[model.Job]],
- workflow_resource_parameters: Optional[dict[str, Any]],
+ tool_request: ToolRequest | None,
+ rerun_remap_job_id: int | None,
+ preferred_object_store_id: str | None,
+ credentials_context: CredentialsContext | None,
+ collection_info: MatchingCollections | None,
+ workflow_invocation_uuid: str | None,
+ invocation_step: model.WorkflowInvocationStep | None,
+ max_num_jobs: int | None,
+ job_callback: Callable | None,
+ completed_jobs: dict[int, model.Job | None],
+ workflow_resource_parameters: dict[str, Any] | None,
validate_outputs: bool,
) -> "ExecutionTracker":
if max_num_jobs is not None:
@@ -285,7 +283,7 @@ def _execute(
)
execution_cache = ToolExecutionCache(trans)
- def execute_single_job(execution_slice: "ExecutionSlice", completed_job: Optional[model.Job], skip: bool = False):
+ def execute_single_job(execution_slice: "ExecutionSlice", completed_job: model.Job | None, skip: bool = False):
job_timer = tool.app.execution_timer_factory.get_timer(
"internals.galaxy.tools.execute.job_single", SINGLE_EXECUTION_SUCCESS_MESSAGE
)
@@ -437,16 +435,16 @@ def _execute(
class ExecutionSlice:
job_index: int
param_combination: ToolStateJobInstancePopulatedT
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT]
- validated_param_combination: Optional[JobInternalToolState] = None
- history: Optional[model.History]
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None
+ validated_param_combination: JobInternalToolState | None = None
+ history: model.History | None
def __init__(
self,
job_index: int,
param_combination: ToolStateJobInstancePopulatedT,
- validated_param_combination: Optional[JobInternalToolState] = None,
- dataset_collection_elements: Optional[DatasetCollectionElementsSliceT] = DEFAULT_DATASET_COLLECTION_ELEMENTS,
+ validated_param_combination: JobInternalToolState | None = None,
+ dataset_collection_elements: DatasetCollectionElementsSliceT | None = DEFAULT_DATASET_COLLECTION_ELEMENTS,
):
self.job_index = job_index
self.param_combination = param_combination
@@ -455,7 +453,7 @@ class ExecutionSlice:
self.history = None
-ExecutionErrorsT = Union[str, Exception]
+ExecutionErrorsT = str | Exception
class ExecutionTracker:
@@ -470,8 +468,8 @@ class ExecutionTracker:
trans,
tool: "Tool",
mapping_params: MappingParameters,
- collection_info: Optional[MatchingCollections],
- completed_jobs: Optional[CompletedJobsT] = None,
+ collection_info: MatchingCollections | None,
+ completed_jobs: CompletedJobsT | None = None,
):
# Known ahead of time...
self.trans = trans
@@ -480,7 +478,7 @@ class ExecutionTracker:
self.collection_info = collection_info
self.completed_jobs = completed_jobs
- self._on_text: Optional[str] = None
+ self._on_text: str | None = None
# Populated as we go...
self.failed_jobs = 0
@@ -497,7 +495,7 @@ class ExecutionTracker:
return self.mapping_params.param_combinations
@property
- def validated_param_combinations(self) -> Sequence[Optional[JobInternalToolState]]:
+ def validated_param_combinations(self) -> Sequence[JobInternalToolState | None]:
if self.mapping_params.validated_param_combinations is not None:
return self.mapping_params.validated_param_combinations
else:
@@ -532,7 +530,7 @@ class ExecutionTracker:
@staticmethod
def _collection_info_to_collection_hids_element_ids(
- items: list[Union[model.DatasetCollectionElement, model.HistoryDatasetCollectionAssociation]],
+ items: list[model.DatasetCollectionElement | model.HistoryDatasetCollectionAssociation],
) -> tuple[list[int], list[str]]:
element_ids = []
collection_hids = []
@@ -546,7 +544,7 @@ class ExecutionTracker:
return collection_hids, element_ids
@property
- def on_text(self) -> Optional[str]:
+ def on_text(self) -> str | None:
collection_info = self.collection_info
if self._on_text is None and collection_info is not None:
collection_hids, element_ids = self._collection_info_to_collection_hids_element_ids(
@@ -656,7 +654,7 @@ class ExecutionTracker:
mapped_output_structure = mapping_structure.multiply(output_structure)
return mapped_output_structure
- def ensure_implicit_collections_populated(self, history, params, tool_request: Optional[ToolRequest]):
+ def ensure_implicit_collections_populated(self, history, params, tool_request: ToolRequest | None):
if not self.collection_info:
return
@@ -664,7 +662,7 @@ class ExecutionTracker:
# params = param_combinations[0] if param_combinations else mapping_params.param_template
self.precreate_output_collections(history, params, tool_request)
- def precreate_output_collections(self, history, params, tool_request: Optional[ToolRequest]):
+ def precreate_output_collections(self, history, params, tool_request: ToolRequest | None):
# params is just one sample tool param execution with parallelized
# collection replaced with a specific dataset. Need to replace this
# with the collection and wrap everything up so can evaluate output
@@ -853,15 +851,15 @@ class ToolExecutionTracker(ExecutionTracker):
trans,
tool: "Tool",
mapping_params: MappingParameters,
- collection_info: Optional[MatchingCollections],
- completed_jobs: Optional[CompletedJobsT] = None,
+ collection_info: MatchingCollections | None,
+ completed_jobs: CompletedJobsT | None = None,
):
super().__init__(trans, tool, mapping_params, collection_info, completed_jobs=completed_jobs)
# New to track these things for tool output API response in the tool case,
# in the workflow case we just write stuff to the database and forget about
# it.
- self.outputs_by_output_name: dict[str, list[Union[model.DatasetInstance, model.DatasetCollection]]] = (
+ self.outputs_by_output_name: dict[str, list[model.DatasetInstance | model.DatasetCollection]] = (
collections.defaultdict(list)
)
@@ -898,9 +896,9 @@ class WorkflowStepExecutionTracker(ExecutionTracker):
trans,
tool: "Tool",
mapping_params: MappingParameters,
- collection_info: Optional[MatchingCollections],
+ collection_info: MatchingCollections | None,
invocation_step: model.WorkflowInvocationStep,
- completed_jobs: Optional[CompletedJobsT] = None,
+ completed_jobs: CompletedJobsT | None = None,
):
super().__init__(trans, tool, mapping_params, collection_info, completed_jobs=completed_jobs)
self.invocation_step = invocation_step
@@ -932,7 +930,7 @@ class WorkflowStepExecutionTracker(ExecutionTracker):
yield ExecutionSlice(job_index, param_combination, validated_param_combination, dataset_collection_elements)
- def ensure_implicit_collections_populated(self, history, params, tool_request: Optional[ToolRequest]):
+ def ensure_implicit_collections_populated(self, history, params, tool_request: ToolRequest | None):
if not self.collection_info:
return
diff --git a/lib/galaxy/tools/execution_helpers.py b/lib/galaxy/tools/execution_helpers.py
index 21c5d295dab..7f1d24ecda8 100644
--- a/lib/galaxy/tools/execution_helpers.py
+++ b/lib/galaxy/tools/execution_helpers.py
@@ -5,7 +5,6 @@ tool execution code, and tool action code.
"""
import logging
-from typing import Optional
from more_itertools import consecutive_groups
@@ -50,7 +49,7 @@ def filter_output(tool, output, incoming):
return False
-def on_text_for_names(names: Optional[list[str]], prefix: Optional[str] = None) -> str:
+def on_text_for_names(names: list[str] | None, prefix: str | None = None) -> str:
if names is None or len(names) == 0:
return ""
@@ -71,7 +70,7 @@ def on_text_for_names(names: Optional[list[str]], prefix: Optional[str] = None)
return on_text
-def on_text_for_numeric_ids(ids: Optional[list[int]], prefix: Optional[str] = None) -> str:
+def on_text_for_numeric_ids(ids: list[int] | None, prefix: str | None = None) -> str:
if ids is None or len(ids) == 0:
return ""
# ids may contain duplicates... this is because the first value in
@@ -92,9 +91,9 @@ def on_text_for_numeric_ids(ids: Optional[list[int]], prefix: Optional[str] = No
def on_text_for_dataset_and_collections(
- dataset_hids: Optional[list[int]] = None,
- collection_hids: Optional[list[int]] = None,
- element_ids: Optional[list[str]] = None,
+ dataset_hids: list[int] | None = None,
+ collection_hids: list[int] | None = None,
+ element_ids: list[str] | None = None,
) -> str:
on_text = []
diff --git a/lib/galaxy/tools/expressions/evaluation.py b/lib/galaxy/tools/expressions/evaluation.py
index 58acd0a51db..d55aa79dfb6 100644
--- a/lib/galaxy/tools/expressions/evaluation.py
+++ b/lib/galaxy/tools/expressions/evaluation.py
@@ -21,9 +21,9 @@ NODE_ENGINE = os.path.join(FILE_DIRECTORY, "cwlNodeEngine.js")
def do_eval(
expression: str,
jobinput: CWLObjectType,
- javascript_requirements: Optional[list[JavascriptRequirement]] = None,
- outdir: Optional[str] = None,
- tmpdir: Optional[str] = None,
+ javascript_requirements: list[JavascriptRequirement] | None = None,
+ outdir: str | None = None,
+ tmpdir: str | None = None,
context: Optional["CWLOutputType"] = None,
):
requirements: list[CWLObjectType] = []
diff --git a/lib/galaxy/tools/fetch/workbooks.py b/lib/galaxy/tools/fetch/workbooks.py
index 1e509b152bf..296675452e9 100644
--- a/lib/galaxy/tools/fetch/workbooks.py
+++ b/lib/galaxy/tools/fetch/workbooks.py
@@ -1,8 +1,6 @@
from dataclasses import dataclass
from typing import (
Literal,
- Optional,
- Union,
)
from openpyxl import Workbook
@@ -108,7 +106,7 @@ WorkbookContentField: Base64StringT = Field(
class ParseFetchWorkbook(BaseModel):
content: Base64StringT = WorkbookContentField
- fill_identifiers: Optional[FillIdentifiers] = None
+ fill_identifiers: FillIdentifiers | None = None
def header_column_to_parsed_column(header_column: HeaderColumn) -> "ParsedColumn":
@@ -149,7 +147,7 @@ def generate(request: GenerateFetchWorkbookRequest) -> Workbook:
return workbook
-ParsedRow = dict[str, Optional[str]]
+ParsedRow = dict[str, str | None]
ParsedRows = list[ParsedRow]
@@ -169,13 +167,14 @@ class InferredCollectionTypeLogEntry(ParseLogEntry):
from_columns: list[ParsedColumn]
-AnyLogMessage = Union[
- SplitUpPairedDataLogEntry,
- InferredCollectionTypeLogEntry,
- InferredColumnMapping,
- ContentTypeMessage,
- CsvDialectInferenceMessage,
-]
+AnyLogMessage = (
+ SplitUpPairedDataLogEntry
+ | InferredCollectionTypeLogEntry
+ | InferredColumnMapping
+ | ContentTypeMessage
+ | CsvDialectInferenceMessage
+)
+
FetchParseLog = list[AnyLogMessage]
@@ -196,7 +195,7 @@ class ParsedFetchWorkbookForCollections(BaseParsedFetchWorkbook):
collection_type: FetchWorkbookCollectionType
-ParsedFetchWorkbook = Union[ParsedFetchWorkbookForDatasets, ParsedFetchWorkbookForCollections]
+ParsedFetchWorkbook = ParsedFetchWorkbookForDatasets | ParsedFetchWorkbookForCollections
def parse(payload: ParseFetchWorkbook) -> ParsedFetchWorkbook:
@@ -308,7 +307,7 @@ def _load_row_data(
def _split_paired_data_if_needed(
rows: ParsedRows, column_headers: list[HeaderColumn]
-) -> tuple[ParsedRows, list[HeaderColumn], Optional[SplitUpPairedDataLogEntry]]:
+) -> tuple[ParsedRows, list[HeaderColumn], SplitUpPairedDataLogEntry | None]:
split_rows: ParsedRows = []
uri_like_columns = _uri_like_columns(column_headers)
if len(_uri_like_columns(column_headers)) != 2:
@@ -383,7 +382,7 @@ def _split_paired_data_if_needed(
def _fill_in_identifier_column_if_needed(
- rows: ParsedRows, columns: list[HeaderColumn], config: Optional[FillIdentifiers]
+ rows: ParsedRows, columns: list[HeaderColumn], config: FillIdentifiers | None
) -> ParsedRows:
list_identifiers_columns = [c for c in columns if c.type == "list_identifiers"]
uri_columns = _uri_like_columns(columns)
@@ -396,7 +395,7 @@ def _fill_in_identifier_column_if_needed(
uri_column = uri_columns[0]
inner_list_identifier_column = list_identifiers_columns[-1]
- uris_to_identifiers: list[tuple[str, Optional[str]]] = []
+ uris_to_identifiers: list[tuple[str, str | None]] = []
for row in rows:
uri = row.get(uri_column.name)
if not uri:
diff --git a/lib/galaxy/tools/imp_exp/__init__.py b/lib/galaxy/tools/imp_exp/__init__.py
index 675a4cee00a..843d4c4297b 100644
--- a/lib/galaxy/tools/imp_exp/__init__.py
+++ b/lib/galaxy/tools/imp_exp/__init__.py
@@ -2,7 +2,6 @@ import getpass
import logging
import os
import shutil
-from typing import Optional
from sqlalchemy import select
@@ -107,7 +106,7 @@ class JobExportHistoryArchiveWrapper:
include_hidden=False,
include_deleted=False,
compressed=True,
- user: Optional[model.User] = None,
+ user: model.User | None = None,
):
"""
Perform setup for job to export a history into an archive.
diff --git a/lib/galaxy/tools/parameters/__init__.py b/lib/galaxy/tools/parameters/__init__.py
index ac962559218..93870d45f9e 100644
--- a/lib/galaxy/tools/parameters/__init__.py
+++ b/lib/galaxy/tools/parameters/__init__.py
@@ -6,8 +6,6 @@ from json import dumps
from typing import (
Any,
cast,
- Optional,
- Union,
)
from boltons.iterutils import remap
@@ -57,7 +55,7 @@ REPLACE_ON_TRUTHY = object()
# Some tools use the code tag and access the code base, expecting certain tool parameters to be available here.
__all__ = ("DataCollectionToolParameter", "DataToolParameter", "SelectToolParameter")
-ToolInputsT = dict[str, Union[Group, ToolParameter]]
+ToolInputsT = dict[str, Group | ToolParameter]
def visit_input_values(
@@ -290,7 +288,7 @@ def visit_input_values(
def check_param(
trans, param: ToolParameter, incoming_value, param_values, simple_errors: bool = True
-) -> tuple[Any, Union[str, ValueError, None]]:
+) -> tuple[Any, str | ValueError | None]:
"""
Check the value of a single parameter `param`. The value in
`incoming_value` is converted from its HTML encoding and validated.
@@ -299,7 +297,7 @@ def check_param(
when dealing with grouping scenarios).
"""
value = incoming_value
- error: Union[str, ValueError, None] = None
+ error: str | ValueError | None = None
try:
if trans.workflow_building_mode:
if is_runtime_value(value):
@@ -334,7 +332,7 @@ def params_to_strings(
app,
nested=False,
use_security=False,
-) -> Union[ToolStateDumpedToJsonT, ToolStateDumpedToJsonInternalT, ToolStateDumpedToStringsT]:
+) -> ToolStateDumpedToJsonT | ToolStateDumpedToJsonInternalT | ToolStateDumpedToStringsT:
"""
Convert a dictionary of parameter values to a dictionary of strings
suitable for persisting. The `value_to_basic` method of each parameter
@@ -354,7 +352,7 @@ def params_to_strings(
return rval
-def params_from_strings(params: dict[str, Union[Group, ToolParameter]], param_values, app, ignore_errors=False) -> dict:
+def params_from_strings(params: dict[str, Group | ToolParameter], param_values, app, ignore_errors=False) -> dict:
"""
Convert a dictionary of strings as produced by `params_to_strings`
back into parameter values (decode the json representation and then
@@ -430,7 +428,7 @@ def populate_state(
inputs: ToolInputsT,
incoming: ToolStateJobInstanceT,
state: ToolStateJobInstancePopulatedT,
- errors: Optional[ParameterValidationErrorsT] = None,
+ errors: ParameterValidationErrorsT | None = None,
context=None,
check=True,
simple_errors=True,
diff --git a/lib/galaxy/tools/parameters/basic.py b/lib/galaxy/tools/parameters/basic.py
index ee2bd373f00..05cbb2c6b8d 100644
--- a/lib/galaxy/tools/parameters/basic.py
+++ b/lib/galaxy/tools/parameters/basic.py
@@ -19,7 +19,6 @@ from typing import (
cast,
Optional,
TYPE_CHECKING,
- Union,
)
from packaging.version import Version
@@ -446,7 +445,7 @@ class TextToolParameter(SimpleTextToolParameter):
return super().validate(value, trans)
@property
- def wrapper_default(self) -> Optional[str]:
+ def wrapper_default(self) -> str | None:
"""Handle change in default handling pre and post 23.0 profiles."""
profile = self.profile
legacy_behavior = profile is None or Version(str(profile)) < Version("23.0")
@@ -1008,7 +1007,7 @@ class SelectToolParameter(ToolParameter):
call_other_values.update(other_values.dict)
return call_other_values
- def get_options(self, trans, other_values) -> Sequence[Union[ParameterOption, DrillDownOptionsDict]]:
+ def get_options(self, trans, other_values) -> Sequence[ParameterOption | DrillDownOptionsDict]:
if self.options:
return self.options.get_options(trans, other_values)
elif self.dynamic_options:
@@ -1176,7 +1175,7 @@ class SelectToolParameter(ToolParameter):
if not self.optional and not self.multiple and options:
# Nothing selected, but not optional and not a multiple select, with some values,
# so we have to default to something (the HTML form will anyway)
- value2: Optional[Union[str, list[str]]] = options[0].value
+ value2: str | list[str] | None = options[0].value
else:
value2 = None
elif len(value) == 1 or not self.multiple:
@@ -1886,9 +1885,9 @@ def _paginated_visible_datasets(
trans: "ProvidesHistoryContext",
history: "History",
*,
- extensions: Optional[set[str]],
- valid_states: Optional[tuple[str, ...]],
- search: Optional[str] = None,
+ extensions: set[str] | None,
+ valid_states: tuple[str, ...] | None,
+ search: str | None = None,
offset: int = 0,
limit: int = 50,
) -> tuple[list[HistoryDatasetAssociation], int]:
@@ -1925,7 +1924,7 @@ def _paginated_dataset_collections(
history: "History",
*,
visible_only: bool,
- search: Optional[str] = None,
+ search: str | None = None,
offset: int = 0,
limit: int = 50,
) -> tuple[list[HistoryDatasetCollectionAssociation], int]:
@@ -2008,7 +2007,7 @@ class BaseDataToolParameter(ToolParameter):
self.options_filter_attribute = options_elem.get("options_filter_attribute", None)
self.is_dynamic = self.options is not None
- def _acceptable_extensions(self) -> Optional[set[str]]:
+ def _acceptable_extensions(self) -> set[str] | None:
"""Return a set of HDA extensions that match this parameter's formats
directly or via implicit conversion. ``None`` means no extension filter
(the parameter accepts all formats)."""
@@ -2017,11 +2016,10 @@ class BaseDataToolParameter(ToolParameter):
return cached
formats = getattr(self, "formats", None)
if not formats:
- self._acceptable_extensions_cache: Optional[set[str]] = None
+ self._acceptable_extensions_cache: set[str] | None = None
return None
accepted: set[str] = set(getattr(self, "extensions", []))
- registry = self.datatypes_registry
- if registry is not None:
+ if (registry := self.datatypes_registry) is not None:
try:
all_exts = list(registry.datatypes_by_extension.keys())
except AttributeError:
@@ -2194,18 +2192,14 @@ class BaseDataToolParameter(ToolParameter):
raise ParameterValueError(f"at most {self.max} datasets are required", self.name)
-ItemFromSrcAny = Union[
- DatasetCollectionElement,
- HistoryDatasetAssociation,
- HistoryDatasetCollectionAssociation,
- LibraryDatasetDatasetAssociation,
- CollectionAdapter,
-]
-ItemFromSrcCollection = Union[
- DatasetCollectionElement,
- HistoryDatasetCollectionAssociation,
- CollectionAdapter,
-]
+ItemFromSrcAny = (
+ DatasetCollectionElement
+ | HistoryDatasetAssociation
+ | HistoryDatasetCollectionAssociation
+ | LibraryDatasetDatasetAssociation
+ | CollectionAdapter
+)
+ItemFromSrcCollection = DatasetCollectionElement | HistoryDatasetCollectionAssociation | CollectionAdapter
def _decode_dataset_id(value, security: "IdEncodingHelper", parameter_name: str) -> int:
@@ -2358,13 +2352,11 @@ class DataToolParameter(BaseDataToolParameter):
if isinstance(value, str) and value.find(",") > 0:
value = [int(value_part) for value_part in value.split(",")]
rval: list[
- Union[
- DatasetCollectionElement,
- HistoryDatasetAssociation,
- HistoryDatasetCollectionAssociation,
- LibraryDatasetDatasetAssociation,
- CollectionAdapter,
- ]
+ DatasetCollectionElement
+ | HistoryDatasetAssociation
+ | HistoryDatasetCollectionAssociation
+ | LibraryDatasetDatasetAssociation
+ | CollectionAdapter
] = []
if isinstance(value, list):
found_srcs = set()
@@ -2417,13 +2409,13 @@ class DataToolParameter(BaseDataToolParameter):
dataset_matcher_factory = get_dataset_matcher_factory(trans)
dataset_matcher = dataset_matcher_factory.dataset_matcher(self, other_values)
for v in rval:
- value_to_check: Union[
- DatasetInstance,
- DatasetCollection,
- DatasetCollectionElement,
- HistoryDatasetCollectionAssociation,
- CollectionAdapter,
- ] = v
+ value_to_check: (
+ DatasetInstance
+ | DatasetCollection
+ | DatasetCollectionElement
+ | HistoryDatasetCollectionAssociation
+ | CollectionAdapter
+ ) = v
if isinstance(v, DatasetCollectionElement):
if hda := v.hda:
value_to_check = hda
@@ -2567,7 +2559,7 @@ class DataToolParameter(BaseDataToolParameter):
ref = ref()
return str(ref)
- def to_dict(self, trans, other_values=None, pagination: Optional[ParameterPaginationT] = None):
+ def to_dict(self, trans, other_values=None, pagination: ParameterPaginationT | None = None):
other_values = other_values or {}
d = super().to_dict(trans)
self._fill_to_dict_static(d)
@@ -2820,7 +2812,7 @@ class DataCollectionToolParameter(BaseDataToolParameter):
)
@property
- def collection_types(self) -> Optional[list[str]]:
+ def collection_types(self) -> list[str] | None:
return self._collection_types
def _history_query(self, trans):
@@ -2856,7 +2848,7 @@ class DataCollectionToolParameter(BaseDataToolParameter):
session = trans.sa_session
other_values = other_values or {}
- rval: Optional[ItemFromSrcCollection] = None
+ rval: ItemFromSrcCollection | None = None
if trans.workflow_building_mode is workflow_building_modes.ENABLED:
return None
if not value and not self.optional and not self.default_object:
@@ -2926,7 +2918,7 @@ class DataCollectionToolParameter(BaseDataToolParameter):
display_text = "No dataset collection."
return display_text
- def to_dict(self, trans, other_values=None, pagination: Optional[ParameterPaginationT] = None):
+ def to_dict(self, trans, other_values=None, pagination: ParameterPaginationT | None = None):
other_values = other_values or {}
d = super().to_dict(trans)
d["collection_types"] = self.collection_types
@@ -3283,7 +3275,7 @@ def history_item_to_json(value, app, use_security):
src = None
# unwrap adapter
- collection_adapter: Optional[CollectionAdapter] = None
+ collection_adapter: CollectionAdapter | None = None
if isinstance(value, CollectionAdapter):
collection_adapter = value
return collection_adapter.to_adapter_model().model_dump()
diff --git a/lib/galaxy/tools/parameters/cancelable_request.py b/lib/galaxy/tools/parameters/cancelable_request.py
index 635760e0449..9c5fca962a8 100644
--- a/lib/galaxy/tools/parameters/cancelable_request.py
+++ b/lib/galaxy/tools/parameters/cancelable_request.py
@@ -3,7 +3,6 @@ import logging
from typing import (
Any,
Literal,
- Optional,
)
import aiohttp
@@ -16,9 +15,9 @@ REQUEST_METHOD = Literal["GET", "POST", "HEAD"]
async def fetch_url(
session: aiohttp.ClientSession,
url: str,
- params: Optional[dict[str, Any]] = None,
- data: Optional[dict[str, Any]] = None,
- headers: Optional[dict[str, Any]] = None,
+ params: dict[str, Any] | None = None,
+ data: dict[str, Any] | None = None,
+ headers: dict[str, Any] | None = None,
method: REQUEST_METHOD = "GET",
):
async with session.request(method=method, url=url, params=params, data=data, headers=headers) as response:
@@ -27,9 +26,9 @@ async def fetch_url(
async def async_request_with_timeout(
url: str,
- params: Optional[dict[str, Any]] = None,
- data: Optional[dict[str, Any]] = None,
- headers: Optional[dict[str, Any]] = None,
+ params: dict[str, Any] | None = None,
+ data: dict[str, Any] | None = None,
+ headers: dict[str, Any] | None = None,
method: REQUEST_METHOD = "GET",
timeout: float = 1.0,
):
@@ -48,9 +47,9 @@ async def async_request_with_timeout(
def request(
url: str,
- params: Optional[dict[str, Any]] = None,
- data: Optional[dict[str, Any]] = None,
- headers: Optional[dict[str, Any]] = None,
+ params: dict[str, Any] | None = None,
+ data: dict[str, Any] | None = None,
+ headers: dict[str, Any] | None = None,
method: REQUEST_METHOD = "GET",
timeout: float = 1.0,
):
diff --git a/lib/galaxy/tools/parameters/dynamic_options.py b/lib/galaxy/tools/parameters/dynamic_options.py
index 038c17f1420..1a64adc8a25 100644
--- a/lib/galaxy/tools/parameters/dynamic_options.py
+++ b/lib/galaxy/tools/parameters/dynamic_options.py
@@ -16,7 +16,6 @@ from typing import (
cast,
get_args,
Literal,
- Optional,
)
from galaxy.model import (
@@ -186,7 +185,7 @@ class DataMetaFilter(Filter):
def get_dependency_name(self):
return self.ref_name
- def filter_options(self, options: Sequence[ParameterOption], trans: Optional[WorkRequestContext], other_values):
+ def filter_options(self, options: Sequence[ParameterOption], trans: WorkRequestContext | None, other_values):
options = list(options)
if trans and trans.workflow_building_mode is workflow_building_modes.USE_HISTORY:
# We're in the run form, can't possibly apply a data_meta filter.
@@ -1021,19 +1020,19 @@ REQUEST_METHODS = Literal["GET", "POST"]
class FromUrlOptions:
from_url: str
request_method: REQUEST_METHODS
- request_body: Optional[str]
- request_headers: Optional[str]
- postprocess_expression: Optional[str]
+ request_body: str | None
+ request_headers: str | None
+ postprocess_expression: str | None
-def strip_or_none(maybe_string: Optional[Element]) -> Optional[str]:
+def strip_or_none(maybe_string: Element | None) -> str | None:
if maybe_string is not None:
if maybe_string.text:
return maybe_string.text.strip()
return None
-def parse_from_url_options(elem: Element) -> Optional[FromUrlOptions]:
+def parse_from_url_options(elem: Element) -> FromUrlOptions | None:
if from_url := elem.get("from_url"):
request_method = cast(Literal["GET", "POST"], elem.get("request_method", "GET"))
assert request_method in get_args(REQUEST_METHODS)
@@ -1050,7 +1049,7 @@ def parse_from_url_options(elem: Element) -> Optional[FromUrlOptions]:
return None
-def template_or_none(template: Optional[str], context: dict[str, Any]) -> Optional[str]:
+def template_or_none(template: str | None, context: dict[str, Any]) -> str | None:
if template:
return fill_template(template, context=context)
return None
diff --git a/lib/galaxy/tools/parameters/grouping.py b/lib/galaxy/tools/parameters/grouping.py
index eacbba661b8..fe9147ecb47 100644
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -14,7 +14,6 @@ from collections.abc import (
from math import inf
from typing import (
Any,
- Optional,
TYPE_CHECKING,
)
@@ -264,10 +263,10 @@ class Dataset(Bunch):
datatype: data.Data
warnings: list[str]
metadata: dict[str, str]
- composite_files: dict[str, Optional[str]]
- uuid: Optional[str]
- tag_using_filenames: Optional[str]
- tags: Optional[str]
+ composite_files: dict[str, str | None]
+ uuid: str | None
+ tag_using_filenames: str | None
+ tags: str | None
name: str
primary_file: str
to_posix_lines: bool
@@ -753,9 +752,9 @@ class Conditional(Group):
def __init__(self, name: str):
Group.__init__(self, name)
- self.test_param: Optional[ToolParameter] = None
+ self.test_param: ToolParameter | None = None
self.cases = []
- self.value_ref: Optional[str] = None
+ self.value_ref: str | None = None
self.value_ref_in_group = True # When our test_param is not part of the conditional Group, this is False
@property
diff --git a/lib/galaxy/tools/parameters/meta.py b/lib/galaxy/tools/parameters/meta.py
index 0a85e805e93..49646cae02b 100644
--- a/lib/galaxy/tools/parameters/meta.py
+++ b/lib/galaxy/tools/parameters/meta.py
@@ -4,8 +4,6 @@ import logging
from collections import namedtuple
from typing import (
Any,
- Optional,
- Union,
)
from galaxy import (
@@ -182,7 +180,7 @@ def expand_workflow_inputs(param_inputs, inputs=None):
return WorkflowParameterExpansion(param_combinations, params_keys, input_combinations)
-ExpandedT = tuple[list[ToolStateJobInstanceT], Optional[matching.MatchingCollections]]
+ExpandedT = tuple[list[ToolStateJobInstanceT], matching.MatchingCollections | None]
def expand_flat_parameters_to_nested(incoming_copy: ToolRequestT) -> dict[str, Any]:
@@ -359,7 +357,7 @@ def split_inputs_nested(inputs, nested_dict, classifier):
ExpandedAsyncT = tuple[
- list[ToolStateJobInstanceT], list[ToolStateDumpedToJsonInternalT], Optional[matching.MatchingCollections]
+ list[ToolStateJobInstanceT], list[ToolStateDumpedToJsonInternalT], matching.MatchingCollections | None
]
@@ -436,9 +434,9 @@ def to_decoded_json(has_objects):
return has_objects
-CollectionExpansionListT = Union[
- list[Union[DatasetCollectionElement, PromoteCollectionElementToCollectionAdapter]], list[DatasetInstance]
-]
+CollectionExpansionListT = (
+ list[DatasetCollectionElement | PromoteCollectionElementToCollectionAdapter] | list[DatasetInstance]
+)
def __expand_collection_parameter(
@@ -475,7 +473,7 @@ def __expand_collection_parameter(
raise exceptions.ToolInputsNotReadyException("An input collection is not populated.")
collections_to_match.add(input_key, item, subcollection_type=subcollection_type, linked=linked)
if subcollection_type is not None:
- subcollection_elements: list[Union[DatasetCollectionElement, PromoteCollectionElementToCollectionAdapter]] = (
+ subcollection_elements: list[DatasetCollectionElement | PromoteCollectionElementToCollectionAdapter] = (
subcollections._split_dataset_collection(collection, subcollection_type)
)
return subcollection_elements
diff --git a/lib/galaxy/tools/parameters/pagination.py b/lib/galaxy/tools/parameters/pagination.py
index 28b743b4cd9..79bb5c19f13 100644
--- a/lib/galaxy/tools/parameters/pagination.py
+++ b/lib/galaxy/tools/parameters/pagination.py
@@ -8,9 +8,7 @@ from collections.abc import (
)
from typing import (
Any,
- Optional,
TypeVar,
- Union,
)
DEFAULT_OPTIONS_PAGE_SIZE = 50
@@ -27,7 +25,7 @@ OptionsPaginationT = Mapping[str, ParameterPaginationT]
T = TypeVar("T")
-def normalize_pagination(pagination: Optional[ParameterPaginationT], src: str) -> tuple[int, int, Optional[str]]:
+def normalize_pagination(pagination: ParameterPaginationT | None, src: str) -> tuple[int, int, str | None]:
"""Return a clamped ``(offset, limit, search)`` for ``src``.
Falls back to ``(0, DEFAULT_OPTIONS_PAGE_SIZE, None)`` when no spec is
@@ -44,7 +42,7 @@ def normalize_pagination(pagination: Optional[ParameterPaginationT], src: str) -
limit = int(spec.get("limit", DEFAULT_OPTIONS_PAGE_SIZE))
limit = min(max(limit, 1), MAX_OPTIONS_PAGE_SIZE)
raw_search = spec.get("search")
- search: Optional[str] = None
+ search: str | None = None
if isinstance(raw_search, str) and raw_search.strip():
search = raw_search.strip()
return offset, limit, search
@@ -52,10 +50,10 @@ def normalize_pagination(pagination: Optional[ParameterPaginationT], src: str) -
def accumulate_with_filter(
query_fn: Callable[..., tuple[list, int]],
- filter_fn: Callable[[Any], Union[None, T, list[T]]],
+ filter_fn: Callable[[Any], None | T | list[T]],
post_filter_offset: int,
limit: int,
- chunk_size: Optional[int] = None,
+ chunk_size: int | None = None,
) -> tuple[list[T], int, bool]:
"""Walk DB chunks via ``query_fn(offset=, limit=)`` and apply ``filter_fn``.
@@ -164,8 +162,8 @@ def make_hdca_entry(
hdca,
name: str,
*,
- keep: Optional[bool] = None,
- subcollection_type: Optional[str] = None,
+ keep: bool | None = None,
+ subcollection_type: str | None = None,
include_column_definitions: bool = False,
) -> dict[str, Any]:
"""Build an ``options.hdca`` / ``pinned.hdca`` entry.
@@ -234,8 +232,8 @@ class DataOptionsBuilder:
def __init__(
self,
security,
- pagination: Optional[ParameterPaginationT] = None,
- sources: Optional[tuple[str, ...]] = None,
+ pagination: ParameterPaginationT | None = None,
+ sources: tuple[str, ...] | None = None,
):
"""``sources`` overrides which keys appear in ``options``/``pinned`` —
``DataCollectionToolParameter`` historically omits ``ldda``, so its
@@ -247,16 +245,15 @@ class DataOptionsBuilder:
self.options: dict[str, list[dict[str, Any]]] = {s: [] for s in self._sources}
self.pinned: dict[str, list[dict[str, Any]]] = {s: [] for s in self._sources}
self.options_meta: dict[str, dict[str, Any]] = {}
- self._page_cache: dict[str, tuple[int, int, Optional[str]]] = {}
+ self._page_cache: dict[str, tuple[int, int, str | None]] = {}
- def page(self, src: str) -> tuple[int, int, Optional[str]]:
+ def page(self, src: str) -> tuple[int, int, str | None]:
"""Return the ``(offset, limit, search)`` triple for ``src`` per the
request's pagination spec (clamped + defaulted). Memoized so callers
and ``paginate()`` see the same normalized values even if
``normalize_pagination`` ever becomes non-pure.
"""
- cached = self._page_cache.get(src)
- if cached is not None:
+ if (cached := self._page_cache.get(src)) is not None:
return cached
triple = normalize_pagination(self._pagination, src)
self._page_cache[src] = triple
@@ -267,7 +264,7 @@ class DataOptionsBuilder:
src: str,
*,
query: Callable[..., tuple[list[Any], int]],
- filter: Callable[[Any], Union[None, T, list[T]]],
+ filter: Callable[[Any], None | T | list[T]],
chunked: bool = True,
) -> tuple[list[T], int, bool]:
"""Run a paginated query+filter for ``src`` and record its
diff --git a/lib/galaxy/tools/parameters/populate_model.py b/lib/galaxy/tools/parameters/populate_model.py
index 6495fade2b7..49d531255ec 100644
--- a/lib/galaxy/tools/parameters/populate_model.py
+++ b/lib/galaxy/tools/parameters/populate_model.py
@@ -1,6 +1,5 @@
from typing import (
Any,
- Optional,
)
from galaxy.util.expressions import ExpressionContext
@@ -14,7 +13,7 @@ def populate_model(
state_inputs,
group_inputs: list[dict[str, Any]],
other_values=None,
- options_pagination: Optional[OptionsPaginationT] = None,
+ options_pagination: OptionsPaginationT | None = None,
name_prefix: str = "",
):
"""
diff --git a/lib/galaxy/tools/parameters/validation.py b/lib/galaxy/tools/parameters/validation.py
index fdd75e7c30e..dfd5880d499 100644
--- a/lib/galaxy/tools/parameters/validation.py
+++ b/lib/galaxy/tools/parameters/validation.py
@@ -8,8 +8,6 @@ import os
from typing import (
Any,
cast,
- Optional,
- Union,
)
from galaxy import (
@@ -106,8 +104,8 @@ class InRangeValidator(ExpressionValidator):
def __init__(
self,
message: str,
- min: Optional[float] = None,
- max: Optional[float] = None,
+ min: float | None = None,
+ max: float | None = None,
exclude_min: bool = False,
exclude_max: bool = False,
negate: bool = False,
@@ -135,7 +133,7 @@ class InRangeValidator(ExpressionValidator):
super().__init__(message, expression, negate)
@staticmethod
- def simple_range_validator(min: Optional[float], max: Optional[float]):
+ def simple_range_validator(min: float | None, max: float | None):
return cast(
InRangeParameterValidatorModel,
_to_validator(None, InRangeParameterValidatorModel(min=min, max=max, implicit=True)),
@@ -205,8 +203,8 @@ class MetadataValidator(Validator):
def __init__(
self,
message: str,
- check: Optional[list[str]] = None,
- skip: Optional[list[str]] = None,
+ check: list[str] | None = None,
+ skip: list[str] | None = None,
negate: bool = False,
):
super().__init__(message, negate)
@@ -306,7 +304,7 @@ class MetadataInFileColumnValidator(Validator):
metadata_name: str,
metadata_column: int,
message: str,
- line_startswith: Optional[str] = None,
+ line_startswith: str | None = None,
split: str = "\t",
negate: bool = False,
):
@@ -341,7 +339,7 @@ class ValueInDataTableColumnValidator(Validator):
def __init__(
self,
tool_data_table,
- metadata_column: Union[str, int],
+ metadata_column: str | int,
message: str,
negate: bool = False,
):
@@ -382,7 +380,7 @@ class ValueNotInDataTableColumnValidator(ValueInDataTableColumnValidator):
"""
def __init__(
- self, tool_data_table, metadata_column: Union[str, int], message="Value already present.", negate: bool = False
+ self, tool_data_table, metadata_column: str | int, message="Value already present.", negate: bool = False
):
super().__init__(tool_data_table, metadata_column, message, negate)
@@ -408,7 +406,7 @@ class MetadataInDataTableColumnValidator(ValueInDataTableColumnValidator):
self,
tool_data_table,
metadata_name: str,
- metadata_column: Union[str, int],
+ metadata_column: str | int,
message: str,
negate: bool = False,
):
@@ -435,7 +433,7 @@ class MetadataNotInDataTableColumnValidator(MetadataInDataTableColumnValidator):
self,
tool_data_table,
metadata_name: str,
- metadata_column: Union[str, int],
+ metadata_column: str | int,
message: str,
negate: bool = False,
):
@@ -463,8 +461,8 @@ class MetadataInRangeValidator(InRangeValidator):
self,
metadata_name: str,
message: str,
- min: Optional[float] = None,
- max: Optional[float] = None,
+ min: float | None = None,
+ max: float | None = None,
exclude_min: bool = False,
exclude_max: bool = False,
negate: bool = False,
diff --git a/lib/galaxy/tools/parameters/workflow_utils.py b/lib/galaxy/tools/parameters/workflow_utils.py
index a63f290cd80..10239af618c 100644
--- a/lib/galaxy/tools/parameters/workflow_utils.py
+++ b/lib/galaxy/tools/parameters/workflow_utils.py
@@ -3,7 +3,6 @@ from typing import Literal
class NoReplacement:
-
def __str__(self):
return "NO_REPLACEMENT singleton"
diff --git a/lib/galaxy/tools/parameters/wrapped.py b/lib/galaxy/tools/parameters/wrapped.py
index 8355cfef033..728a81f0957 100644
--- a/lib/galaxy/tools/parameters/wrapped.py
+++ b/lib/galaxy/tools/parameters/wrapped.py
@@ -2,9 +2,7 @@ from collections import UserDict
from collections.abc import Sequence
from typing import (
Any,
- Optional,
TYPE_CHECKING,
- Union,
)
from galaxy.exceptions import RequestParameterInvalidException
@@ -78,7 +76,7 @@ class WrappedParameters:
trans,
tool: "Tool",
incoming: "ToolStateJobInstancePopulatedT",
- input_datasets: Optional[LegacyUnprefixedDict] = None,
+ input_datasets: LegacyUnprefixedDict | None = None,
):
self.trans = trans
self.tool = tool
@@ -210,13 +208,13 @@ def process_key(incoming_key: str, incoming_value: Any, d: dict[str, Any]):
process_key("|".join(key_parts[1:]), incoming_value=incoming_value, d=subdict)
-def nested_key_to_path(key: str) -> Sequence[Union[str, int]]:
+def nested_key_to_path(key: str) -> Sequence[str | int]:
"""
Convert a tool state key that is separated with '|' and '_n' into path iterable.
E.g. "cond|repeat_0|paramA" -> ["cond", "repeat", 0, "paramA"].
Return value can be used with `boltons.iterutils.get_path`.
"""
- path: list[Union[str, int]] = []
+ path: list[str | int] = []
key_parts = key.split("|")
if len(key_parts) == 1:
return key_parts
diff --git a/lib/galaxy/tools/remote_tool_eval.py b/lib/galaxy/tools/remote_tool_eval.py
index 6cde4936535..04ab375d227 100644
--- a/lib/galaxy/tools/remote_tool_eval.py
+++ b/lib/galaxy/tools/remote_tool_eval.py
@@ -120,7 +120,7 @@ def main(TMPDIR, WORKING_DIRECTORY, IMPORT_STORE_DIRECTORY) -> None:
tool_evaluator.set_compute_environment(compute_environment=SharedComputeEnvironment(job_io=job_io, job=job_io.job))
with open(os.path.join(WORKING_DIRECTORY, "tool_script.sh"), "a") as out:
command_line, version_command_line, extra_filenames, environment_variables, *_ = tool_evaluator.build()
- out.write(f'{version_command_line or ""}{command_line}')
+ out.write(f"{version_command_line or ''}{command_line}")
if __name__ == "__main__":
diff --git a/lib/galaxy/tools/repositories.py b/lib/galaxy/tools/repositories.py
index 206d6632d0b..42efffd3480 100644
--- a/lib/galaxy/tools/repositories.py
+++ b/lib/galaxy/tools/repositories.py
@@ -4,7 +4,6 @@ import os
import shutil
import tempfile
from contextlib import contextmanager
-from typing import Optional
from galaxy.managers.dbkeys import GenomeBuilds
from galaxy.tools.data import ToolDataTableManager
@@ -12,13 +11,13 @@ from galaxy.util.bunch import Bunch
class ValidationContextConfig:
- tool_data_path: Optional[str]
- shed_tool_data_path: Optional[str]
+ tool_data_path: str | None
+ shed_tool_data_path: str | None
tool_data_table_config: str
shed_tool_data_table_config: str
interactivetools_enable: bool
len_file_path: str
- builds_file_path: Optional[str]
+ builds_file_path: str | None
class ValidationContext:
diff --git a/lib/galaxy/tools/runtime.py b/lib/galaxy/tools/runtime.py
index eaf84e16ccf..b1b51c383c2 100644
--- a/lib/galaxy/tools/runtime.py
+++ b/lib/galaxy/tools/runtime.py
@@ -3,7 +3,6 @@ from typing import (
Any,
Optional,
TYPE_CHECKING,
- Union,
)
from galaxy.model import (
@@ -32,11 +31,11 @@ if TYPE_CHECKING:
# Type aliases for callbacks
DatasetToRuntimeJson = Callable[[DataJobInternalT], DataInternalJson]
-CollectionToRuntimeJson = Callable[[DataCollectionRequestInternal, Optional[str]], DataCollectionInternalJsonBase]
+CollectionToRuntimeJson = Callable[[DataCollectionRequestInternal, str | None], DataCollectionInternalJsonBase]
# Input dataset collections dict type - values are HDCAs (from job.input_dataset_collections)
# or DCEs (from job.input_dataset_collection_elements for subcollection mapping).
-InpDataCollectionsDictT = dict[str, Union[HistoryDatasetCollectionAssociation, DatasetCollectionElement]]
+InpDataCollectionsDictT = dict[str, HistoryDatasetCollectionAssociation | DatasetCollectionElement]
def is_list_like(collection_type: str) -> bool:
@@ -53,7 +52,7 @@ def setup_for_runtimeify(
app: "MinimalToolApp",
compute_environment: Optional["ComputeEnvironment"],
input_datasets: InpDataDictT,
- input_dataset_collections: Optional[InpDataCollectionsDictT] = None,
+ input_dataset_collections: InpDataCollectionsDictT | None = None,
):
"""Set up callbacks for runtimeify to convert tool state to runtime representations.
@@ -115,7 +114,7 @@ def setup_for_runtimeify(
def adapt_collection(
value: DataCollectionRequestInternal,
- collection_type: Optional[str],
+ collection_type: str | None,
) -> DataCollectionInternalJsonBase:
"""Convert a collection request to runtime representation.
@@ -134,8 +133,7 @@ def setup_for_runtimeify(
return _adapt_from_dce(dce, adapt_dataset, compute_environment)
# Handle HDCA reference (direct collection input)
- hdca = hdcas_by_id.get(value.id)
- if hdca:
+ if hdca := hdcas_by_id.get(value.id):
return _adapt_from_hdca(hdca, adapt_dataset, compute_environment)
raise ValueError(f"Collection {value.id} not found (src={value.src})")
@@ -181,11 +179,11 @@ def _adapt_from_dce(
def collection_to_runtime(
collection: DatasetCollection,
- name: Optional[str],
+ name: str | None,
tags: list[str],
adapt_dataset: DatasetToRuntimeJson,
compute_environment: Optional["ComputeEnvironment"],
- columns: Optional[list] = None,
+ columns: list | None = None,
) -> DataCollectionInternalJsonBase:
"""Convert DatasetCollection to validated typed runtime model."""
raw = _build_collection_runtime_dict(collection, name, tags, adapt_dataset, compute_environment, columns)
@@ -199,19 +197,18 @@ def _validate_collection_runtime_dict(raw: dict[str, Any]) -> DataCollectionInte
which handles both leaf types and nested types with precise inner type validation.
"""
ct = raw.get("collection_type", "")
- model = build_collection_model_for_type(ct)
- if model is not None:
+ if (model := build_collection_model_for_type(ct)) is not None:
return model.model_validate(raw)
raise ValueError(f"Cannot build runtime model for collection_type: '{ct}'")
def _build_collection_runtime_dict(
collection: DatasetCollection,
- name: Optional[str],
+ name: str | None,
tags: list[str],
adapt_dataset: DatasetToRuntimeJson,
compute_environment: Optional["ComputeEnvironment"],
- columns: Optional[list] = None, # from parent DCE for sample_sheet elements
+ columns: list | None = None, # from parent DCE for sample_sheet elements
) -> dict[str, Any]:
"""Convert DatasetCollection to runtime representation.
diff --git a/lib/galaxy/tools/search/__init__.py b/lib/galaxy/tools/search/__init__.py
index e6e0ee4c2bf..92ea32d2a60 100644
--- a/lib/galaxy/tools/search/__init__.py
+++ b/lib/galaxy/tools/search/__init__.py
@@ -31,7 +31,6 @@ import re
import shutil
from typing import (
TYPE_CHECKING,
- Union,
)
from whoosh import (
@@ -72,8 +71,8 @@ if TYPE_CHECKING:
log = logging.getLogger(__name__)
-CanConvertToFloat = Union[str, int, float]
-CanConvertToInt = Union[str, int, float]
+CanConvertToFloat = str | int | float
+CanConvertToInt = str | int | float
def get_or_create_index(index_dir: "StrPath", schema: Schema) -> index.FileIndex:
@@ -289,7 +288,7 @@ class ToolPanelViewSearch:
self,
tool: "Tool",
index_help: bool = True,
- ) -> dict[str, Union[str, list[str]]]:
+ ) -> dict[str, str | list[str]]:
def clean(s: str) -> str:
"""Remove hyphens as they are Whoosh wildcards."""
if "-" in s:
@@ -300,7 +299,7 @@ class ToolPanelViewSearch:
if tool.tool_type == "manage_data":
# Do not add data managers to the public index
return {}
- add_doc_kwds: dict[str, Union[str, list[str]]] = {
+ add_doc_kwds: dict[str, str | list[str]] = {
"id": unicodify(tool.id),
"id_exact": unicodify(tool.id),
"name": clean(tool.name),
diff --git a/lib/galaxy/tools/wrappers.py b/lib/galaxy/tools/wrappers.py
index 7f87a08fcff..62a6ffecec9 100644
--- a/lib/galaxy/tools/wrappers.py
+++ b/lib/galaxy/tools/wrappers.py
@@ -73,7 +73,7 @@ class ToolParameterValueWrapper:
Base class for object that Wraps a Tool Parameter and Value.
"""
- value: Optional[Union[str, list[str]]]
+ value: str | list[str] | None
input: "ToolParameter"
def __bool__(self) -> bool:
@@ -127,9 +127,9 @@ class InputValueWrapper(ToolParameterValueWrapper):
def __init__(
self,
input: "ToolParameter",
- value: Optional[str],
- other_values: Optional[dict[str, str]] = None,
- profile: Optional[float] = None,
+ value: str | None,
+ other_values: dict[str, str] | None = None,
+ profile: float | None = None,
) -> None:
self.input = input
if value is None and input.type == "text":
@@ -138,7 +138,7 @@ class InputValueWrapper(ToolParameterValueWrapper):
self.value = value
self._other_values: dict[str, str] = other_values or {}
- def _get_cast_values(self, other: Any) -> tuple[Union[str, int, float, bool, None], Any]:
+ def _get_cast_values(self, other: Any) -> tuple[str | int | float | bool | None, Any]:
if isinstance(self.input, BooleanToolParameter) and isinstance(other, str):
if other in (self.input.truevalue, self.input.falsevalue):
return str(self), other
@@ -156,7 +156,7 @@ class InputValueWrapper(ToolParameterValueWrapper):
"float": float,
"boolean": bool,
}
- return cast(Union[str, int, float, bool], cast_table.get(self.input.type, str)(self)), other
+ return cast(str | int | float | bool, cast_table.get(self.input.type, str)(self)), other
def __eq__(self, other: Any) -> bool:
casted_self, casted_other = self._get_cast_values(other)
@@ -210,8 +210,8 @@ class SelectToolParameterWrapper(ToolParameterValueWrapper):
def __init__(
self,
input: "SelectToolParameter",
- value: Union[str, list[str]],
- other_values: Optional[dict[str, str]],
+ value: str | list[str],
+ other_values: dict[str, str] | None,
compute_environment: Optional["ComputeEnvironment"],
) -> None:
self._input = input
@@ -245,12 +245,12 @@ class SelectToolParameterWrapper(ToolParameterValueWrapper):
def __init__(
self,
input: "SelectToolParameter",
- value: Union[str, list[str]],
- other_values: Optional[dict[str, str]] = None,
+ value: str | list[str],
+ other_values: dict[str, str] | None = None,
compute_environment: Optional["ComputeEnvironment"] = None,
):
self.input = input
- self.value: Union[str, list[str]] = value
+ self.value: str | list[str] = value
self.input.value_label = input.value_to_display_text(value)
self._other_values = other_values or {}
self.compute_environment = compute_environment
@@ -291,7 +291,7 @@ class DatasetFilenameWrapper(ToolParameterValueWrapper):
attributes are accessible.
"""
- false_path: Optional[str]
+ false_path: str | None
class MetadataWrapper:
"""
@@ -352,17 +352,17 @@ class DatasetFilenameWrapper(ToolParameterValueWrapper):
def __init__(
self,
- dataset: Optional[Union[DatasetInstance, DatasetCollectionElement]],
+ dataset: DatasetInstance | DatasetCollectionElement | None,
datatypes_registry: Optional["Registry"] = None,
tool: Optional["Tool"] = None,
- name: Optional[str] = None,
+ name: str | None = None,
compute_environment: Optional["ComputeEnvironment"] = None,
- identifier: Optional[str] = None,
+ identifier: str | None = None,
io_type: str = "input",
- formats: Optional[list[str]] = None,
+ formats: list[str] | None = None,
tool_evaluator: Optional["ToolEvaluator"] = None,
) -> None:
- dataset_instance: Optional[DatasetInstance] = None
+ dataset_instance: DatasetInstance | None = None
if not dataset:
self.dataset = cast(
DatasetInstance,
@@ -401,7 +401,7 @@ class DatasetFilenameWrapper(ToolParameterValueWrapper):
self.tool_evaluator = tool_evaluator
# TODO: lazy initialize this...
self.__io_type = io_type
- self.false_path: Optional[str] = None
+ self.false_path: str | None = None
if dataset_instance:
if self.__io_type == "input":
path_rewrite = (
@@ -528,14 +528,14 @@ class DatasetFilenameWrapper(ToolParameterValueWrapper):
class HasDatasets:
- job_working_directory: Optional[str]
+ job_working_directory: str | None
@abc.abstractmethod
def __iter__(self) -> Iterator[Any]:
pass
def _dataset_wrapper(
- self, dataset: Optional[Union[DatasetInstance, DatasetCollectionElement]], **kwargs: Any
+ self, dataset: DatasetInstance | DatasetCollectionElement | None, **kwargs: Any
) -> DatasetFilenameWrapper:
return DatasetFilenameWrapper(dataset, **kwargs)
@@ -554,18 +554,10 @@ class DatasetListWrapper(list[DatasetFilenameWrapper], ToolParameterValueWrapper
def __init__(
self,
- job_working_directory: Optional[str],
- datasets: Union[
- Sequence[
- Union[
- None,
- DatasetInstance,
- DatasetCollectionInstance,
- DatasetCollectionElement,
- ]
- ],
- DatasetInstance,
- ],
+ job_working_directory: str | None,
+ datasets: (
+ Sequence[None | DatasetInstance | DatasetCollectionInstance | DatasetCollectionElement] | DatasetInstance
+ ),
**kwargs: Any,
) -> None:
self._dataset_elements_cache: dict[str, list[DatasetFilenameWrapper]] = {}
@@ -573,12 +565,7 @@ class DatasetListWrapper(list[DatasetFilenameWrapper], ToolParameterValueWrapper
datasets = [datasets]
def to_wrapper(
- dataset: Union[
- None,
- DatasetInstance,
- DatasetCollectionInstance,
- DatasetCollectionElement,
- ],
+ dataset: None | DatasetInstance | DatasetCollectionInstance | DatasetCollectionElement,
) -> DatasetFilenameWrapper:
if isinstance(dataset, DatasetCollectionElement):
dataset2 = dataset.dataset_instance
@@ -593,8 +580,8 @@ class DatasetListWrapper(list[DatasetFilenameWrapper], ToolParameterValueWrapper
@staticmethod
def to_dataset_instances(
dataset_instance_sources: Any,
- ) -> list[Union[None, DatasetInstance]]:
- dataset_instances: list[Optional[DatasetInstance]] = []
+ ) -> list[None | DatasetInstance]:
+ dataset_instances: list[DatasetInstance | None] = []
if not isinstance(dataset_instance_sources, list):
dataset_instance_sources = [dataset_instance_sources]
for dataset_instance_source in dataset_instance_sources:
@@ -637,13 +624,13 @@ DatasetCollectionElementWrapper: TypeAlias = Union["DatasetCollectionWrapper", D
class DatasetCollectionWrapper(ToolParameterValueWrapper, HasDatasets):
- name: Optional[str]
+ name: str | None
collection: DatasetCollection
def __init__(
self,
- job_working_directory: Optional[str],
- has_collection: Union[None, DatasetCollectionElement, HistoryDatasetCollectionAssociation],
+ job_working_directory: str | None,
+ has_collection: None | DatasetCollectionElement | HistoryDatasetCollectionAssociation,
datatypes_registry: "Registry",
tool_evaluator: Optional["ToolEvaluator"] = None,
**kwargs: Any,
@@ -651,7 +638,7 @@ class DatasetCollectionWrapper(ToolParameterValueWrapper, HasDatasets):
super().__init__()
self.job_working_directory = job_working_directory
self._dataset_elements_cache: dict[str, list[DatasetFilenameWrapper]] = {}
- self._element_identifiers_extensions_paths_and_metadata_files: Optional[list[list[Any]]] = None
+ self._element_identifiers_extensions_paths_and_metadata_files: list[list[Any]] | None = None
self.datatypes_registry = datatypes_registry
kwargs["datatypes_registry"] = datatypes_registry
self.tool_evaluator = tool_evaluator
@@ -679,7 +666,7 @@ class DatasetCollectionWrapper(ToolParameterValueWrapper, HasDatasets):
element_instances: dict[str, DatasetCollectionElementWrapper] = {}
element_instance_list: list[DatasetCollectionElementWrapper] = []
- rows: dict[str, Optional[SampleSheetRow]] = {}
+ rows: dict[str, SampleSheetRow | None] = {}
for dataset_collection_element in elements:
element_object = dataset_collection_element.element_object
element_identifier = dataset_collection_element.element_identifier
@@ -703,7 +690,7 @@ class DatasetCollectionWrapper(ToolParameterValueWrapper, HasDatasets):
self.__element_instances = element_instances
self.__element_instance_list = element_instance_list
- def sample_sheet_row(self, element_identifier: str) -> Optional[SampleSheetRow]:
+ def sample_sheet_row(self, element_identifier: str) -> SampleSheetRow | None:
return self.__rows[element_identifier]
def get_datasets_for_group(self, group: str) -> list[DatasetFilenameWrapper]:
@@ -724,7 +711,7 @@ class DatasetCollectionWrapper(ToolParameterValueWrapper, HasDatasets):
self._dataset_elements_cache[group] = wrappers
return self._dataset_elements_cache[group]
- def keys(self) -> Union[list[str], KeysView[Any]]:
+ def keys(self) -> list[str] | KeysView[Any]:
if not self.__input_supplied:
return []
return self.__element_instances.keys()
@@ -734,7 +721,7 @@ class DatasetCollectionWrapper(ToolParameterValueWrapper, HasDatasets):
return True
@property
- def element_identifier(self) -> Optional[str]:
+ def element_identifier(self) -> str | None:
return self.name
@property
@@ -809,7 +796,7 @@ class DatasetCollectionWrapper(ToolParameterValueWrapper, HasDatasets):
def is_input_supplied(self) -> bool:
return self.__input_supplied
- def __getitem__(self, key: Union[str, int]) -> Optional[DatasetCollectionElementWrapper]:
+ def __getitem__(self, key: str | int) -> DatasetCollectionElementWrapper | None:
if not self.__input_supplied:
return None
if isinstance(key, int):
@@ -817,7 +804,7 @@ class DatasetCollectionWrapper(ToolParameterValueWrapper, HasDatasets):
else:
return self.__element_instances[key]
- def __getattr__(self, key: str) -> Optional[DatasetCollectionElementWrapper]:
+ def __getattr__(self, key: str) -> DatasetCollectionElementWrapper | None:
if not self.__input_supplied:
return None
try:
@@ -843,13 +830,13 @@ class DatasetCollectionWrapper(ToolParameterValueWrapper, HasDatasets):
class ElementIdentifierMapper:
"""Track mapping of dataset collection elements datasets to element identifiers."""
- def __init__(self, input_datasets: Optional[dict[str, Any]] = None) -> None:
+ def __init__(self, input_datasets: dict[str, Any] | None = None) -> None:
if input_datasets is not None:
self.identifier_key_dict = {v: f"{k}|__identifier__" for k, v in input_datasets.items()}
else:
self.identifier_key_dict = {}
- def identifier(self, dataset_value: str, input_values: dict[str, str]) -> Optional[str]:
+ def identifier(self, dataset_value: str, input_values: dict[str, str]) -> str | None:
if isinstance(dataset_value, list):
raise TypeError(f"Expected {dataset_value} to be hashable")
element_identifier = None
diff --git a/lib/galaxy/util/__init__.py b/lib/galaxy/util/__init__.py
index 884adcc7916..8c2cf005832 100644
--- a/lib/galaxy/util/__init__.py
+++ b/lib/galaxy/util/__init__.py
@@ -26,6 +26,11 @@ import time
import unicodedata
import uuid
import xml.dom.minidom
+from collections.abc import (
+ Iterable,
+ Iterator,
+ Mapping,
+)
from datetime import (
datetime,
timezone,
@@ -38,14 +43,8 @@ from pathlib import Path
from typing import (
Any,
cast,
- Dict,
- Iterable,
- Iterator,
- List,
- Mapping,
- Optional,
+ Literal,
overload,
- Tuple,
TYPE_CHECKING,
TypeVar,
Union,
@@ -63,7 +62,6 @@ from boltons.iterutils import (
remap,
)
from typing_extensions import (
- Literal,
Self,
)
@@ -96,20 +94,19 @@ try:
def __iter__(self) -> Iterator[Self]: # type: ignore[override]
return cast(Iterator[Self], super().__iter__())
- def find(self, path: str, namespaces: Optional[Mapping[str, str]] = None) -> Union[Self, None]:
- ret = super().find(path, namespaces)
- if ret is not None:
+ def find(self, path: str, namespaces: Mapping[str, str] | None = None) -> Self | None:
+ if (ret := super().find(path, namespaces)) is not None:
return cast(Self, ret)
else:
return None
- def findall(self, path: str, namespaces: Optional[Mapping[str, str]] = None) -> List[Self]: # type: ignore[override]
- return cast(List[Self], super().findall(path, namespaces))
+ def findall(self, path: str, namespaces: Mapping[str, str] | None = None) -> list[Self]: # type: ignore[override]
+ return cast(list[Self], super().findall(path, namespaces))
- def iterfind(self, path: str, namespaces: Optional[Mapping[str, str]] = None) -> Iterator[Self]:
+ def iterfind(self, path: str, namespaces: Mapping[str, str] | None = None) -> Iterator[Self]:
return cast(Iterator[Self], super().iterfind(path, namespaces))
- def SubElement(parent: Element, tag: str, attrib: Optional[Dict[str, str]] = None, **extra) -> Element:
+ def SubElement(parent: Element, tag: str, attrib: dict[str, str] | None = None, **extra) -> Element:
return cast(Element, etree.SubElement(parent, tag, attrib, **extra))
# lxml.etree.ElementTree is a function that returns a new instance of the
@@ -123,7 +120,7 @@ try:
def getroot(self) -> Element:
return cast(Element, super().getroot())
- def XML(text: Union[str, bytes]) -> Element:
+ def XML(text: str | bytes) -> Element:
return cast(Element, etree.XML(text))
class LocalOnlyResolver(etree.Resolver):
@@ -213,12 +210,7 @@ def str_removeprefix(s: str, prefix: str):
"""
str.removeprefix() equivalent for Python < 3.9
"""
- if sys.version_info >= (3, 9):
- return s.removeprefix(prefix)
- elif s.startswith(prefix):
- return s[len(prefix) :]
- else:
- return s
+ return s.removeprefix(prefix)
@overload
@@ -364,7 +356,7 @@ def file_reader(fp, chunk_size=CHUNK_SIZE):
ItemType = TypeVar("ItemType")
-def chunk_iterable(it: Iterable[ItemType], size: int = 1000) -> Iterator[Tuple[ItemType, ...]]:
+def chunk_iterable(it: Iterable[ItemType], size: int = 1000) -> Iterator[tuple[ItemType, ...]]:
"""
Break an iterable into chunks of ``size`` elements.
@@ -395,7 +387,7 @@ def parse_xml(
fname: Union[StrPath, "Traversable"],
strip_whitespace: bool = True,
remove_comments: bool = True,
- schemafname: Union[StrPath, None] = None,
+ schemafname: StrPath | None = None,
) -> ElementTree:
"""Returns a parsed xml tree"""
parser = None
@@ -453,7 +445,7 @@ def parse_xml_string_to_etree(xml_string: str, strip_whitespace: bool = True) ->
return ElementTree(parse_xml_string(xml_string=xml_string, strip_whitespace=strip_whitespace))
-def xml_to_string(elem: Optional[Element], pretty: bool = False) -> str:
+def xml_to_string(elem: Element | None, pretty: bool = False) -> str:
"""
Returns a string from an xml tree.
"""
@@ -896,7 +888,7 @@ def ready_name_for_url(raw_name: str) -> str:
return slug_base
-def which(file: str) -> Optional[str]:
+def which(file: str) -> str | None:
# http://stackoverflow.com/questions/5226958/which-equivalent-function-in-python
for path in os.environ["PATH"].split(":"):
if os.path.exists(path + "/" + file):
@@ -1128,24 +1120,24 @@ def string_as_bool_or_none(string):
@overload
-def listify(item: Union[None, Literal[False]], do_strip: bool = False) -> List: ...
+def listify(item: None | Literal[False], do_strip: bool = False) -> list: ...
@overload
-def listify(item: str, do_strip: bool = False) -> List[str]: ...
+def listify(item: str, do_strip: bool = False) -> list[str]: ...
@overload
-def listify(item: Union[List[ItemType], Tuple[ItemType, ...]], do_strip: bool = False) -> List[ItemType]: ...
+def listify(item: list[ItemType] | tuple[ItemType, ...], do_strip: bool = False) -> list[ItemType]: ...
# Unfortunately we cannot use ItemType .. -> List[ItemType] in the next overload
# because then that would also match Union types.
@overload
-def listify(item: Any, do_strip: bool = False) -> List: ...
+def listify(item: Any, do_strip: bool = False) -> list: ...
-def listify(item: Any, do_strip: bool = False) -> List:
+def listify(item: Any, do_strip: bool = False) -> list:
"""
Make a single item a single item list.
@@ -1212,7 +1204,7 @@ def unicodify(
error: str = "replace",
strip_null: bool = False,
log_exception: bool = True,
-) -> Optional[str]:
+) -> str | None:
"""
Returns a Unicode string or None.
@@ -1516,7 +1508,7 @@ def docstring_trim(docstring):
return "\n".join(trimmed)
-def metric_prefix(number: Union[int, float], base: int) -> Tuple[float, str]:
+def metric_prefix(number: int | float, base: int) -> tuple[float, str]:
"""
>>> metric_prefix(100, 1000)
(100.0, '')
@@ -1575,7 +1567,7 @@ def shorten_with_metric_prefix(amount: int) -> str:
return str(amount)
-def nice_size(size: Union[float, int, str, Decimal], binary: bool = False) -> str:
+def nice_size(size: float | int | str | Decimal, binary: bool = False) -> str:
"""
Returns a readably formatted string with the size
diff --git a/lib/galaxy/util/bool_expressions.py b/lib/galaxy/util/bool_expressions.py
index fadac8feaa9..d35d86d6c6b 100644
--- a/lib/galaxy/util/bool_expressions.py
+++ b/lib/galaxy/util/bool_expressions.py
@@ -4,11 +4,9 @@ Based on the example: https://github.com/pyparsing/pyparsing/blob/master/example
"""
import logging
-from typing import (
+from collections.abc import (
Callable,
Iterable,
- Optional,
- Set,
)
from pyparsing import (
@@ -124,7 +122,7 @@ class BooleanExpressionEvaluator:
You can pass in different TokenEvaluator implementations to customize how the tokens (or variables) are
converted to a boolean value when evaluating the expression."""
- def __init__(self, evaluator: TokenEvaluator, token_format: Optional[str] = None) -> None:
+ def __init__(self, evaluator: TokenEvaluator, token_format: str | None = None) -> None:
"""Initializes the expression evaluator.
:param evaluator: The custom TokenEvaluator used to transform any token into a boolean.
@@ -172,7 +170,7 @@ class TokenContainedEvaluator(TokenEvaluator):
"""Implements the TokenEvaluator interface to determine if a token is contained
in a particular list of tokens."""
- def __init__(self, tokens: Set[str]) -> None:
+ def __init__(self, tokens: set[str]) -> None:
"""Initializes the token evaluator with the set of tokens that will evaluate to `True`.
:param tokens: The list of tokens that should be evaluated to True.
diff --git a/lib/galaxy/util/checkers.py b/lib/galaxy/util/checkers.py
index 59ad67cba07..1014ca78f80 100644
--- a/lib/galaxy/util/checkers.py
+++ b/lib/galaxy/util/checkers.py
@@ -10,9 +10,7 @@ from io import (
StringIO,
)
from typing import (
- Dict,
IO,
- Tuple,
)
from typing_extensions import Protocol
@@ -32,7 +30,7 @@ HTML_REGEXPS = (
class CompressionChecker(Protocol):
- def __call__(self, file_path: str, check_content: bool = True) -> Tuple[bool, bool]: ...
+ def __call__(self, file_path: str, check_content: bool = True) -> tuple[bool, bool]: ...
def check_html(name, file_path: bool = True) -> bool:
@@ -86,7 +84,7 @@ def check_binary(name, file_path: bool = True) -> bool:
temp.close()
-def check_gzip(file_path: str, check_content: bool = True) -> Tuple[bool, bool]:
+def check_gzip(file_path: str, check_content: bool = True) -> tuple[bool, bool]:
# This method returns a tuple of booleans representing ( is_gzipped, is_valid )
# Make sure we have a gzipped file
try:
@@ -118,7 +116,7 @@ def check_gzip(file_path: str, check_content: bool = True) -> Tuple[bool, bool]:
return (True, True)
-def check_xz(file_path: str, check_content: bool = True) -> Tuple[bool, bool]:
+def check_xz(file_path: str, check_content: bool = True) -> tuple[bool, bool]:
try:
with open(file_path, "rb") as temp:
magic_check = temp.read(6)
@@ -138,7 +136,7 @@ def check_xz(file_path: str, check_content: bool = True) -> Tuple[bool, bool]:
return (True, True)
-def check_bz2(file_path: str, check_content: bool = True) -> Tuple[bool, bool]:
+def check_bz2(file_path: str, check_content: bool = True) -> tuple[bool, bool]:
try:
with open(file_path, "rb") as temp:
magic_check = temp.read(3)
@@ -158,7 +156,7 @@ def check_bz2(file_path: str, check_content: bool = True) -> Tuple[bool, bool]:
return (True, True)
-def check_zip(file_path: str, check_content: bool = True, files=1) -> Tuple[bool, bool]:
+def check_zip(file_path: str, check_content: bool = True, files=1) -> tuple[bool, bool]:
if not zipfile.is_zipfile(file_path):
return (False, False)
@@ -218,7 +216,7 @@ def check_image(file_path: str) -> bool:
return bool(image_type(file_path))
-COMPRESSION_CHECK_FUNCTIONS: Dict[str, CompressionChecker] = {
+COMPRESSION_CHECK_FUNCTIONS: dict[str, CompressionChecker] = {
"gzip": check_gzip,
"bz2": check_bz2,
"xz": check_xz,
diff --git a/lib/galaxy/util/commands.py b/lib/galaxy/util/commands.py
index 5f71a5455b4..65dd05e4bcd 100644
--- a/lib/galaxy/util/commands.py
+++ b/lib/galaxy/util/commands.py
@@ -8,10 +8,6 @@ import sys as _sys
import tempfile
from typing import (
Any,
- Dict,
- List,
- Optional,
- Union,
)
from galaxy.util import (
@@ -56,7 +52,7 @@ def redirect_aware_commmunicate(p, sys=_sys):
return out, err
-def shell(cmds: Union[List[str], str], env: Optional[Dict[str, str]] = None, **kwds: Any) -> int:
+def shell(cmds: list[str] | str, env: dict[str, str] | None = None, **kwds: Any) -> int:
"""Run shell commands with `shell_process` and wait."""
sys = kwds.get("sys", _sys)
assert sys is not None
@@ -69,14 +65,14 @@ def shell(cmds: Union[List[str], str], env: Optional[Dict[str, str]] = None, **k
return p.wait()
-def shell_process(cmds: Union[List[str], str], env: Optional[Dict[str, str]] = None, **kwds: Any) -> subprocess.Popen:
+def shell_process(cmds: list[str] | str, env: dict[str, str] | None = None, **kwds: Any) -> subprocess.Popen:
"""A high-level method wrapping subprocess.Popen.
Handles details such as environment extension and in process I/O
redirection.
"""
sys = kwds.get("sys", _sys)
- popen_kwds: Dict[str, Any] = {}
+ popen_kwds: dict[str, Any] = {}
if isinstance(cmds, str):
log.warning("Passing program arguments as a string may be a security hazard if combined with untrusted input")
popen_kwds["shell"] = True
diff --git a/lib/galaxy/util/compression_utils.py b/lib/galaxy/util/compression_utils.py
index 3e85cd9aca1..54e7c435a14 100644
--- a/lib/galaxy/util/compression_utils.py
+++ b/lib/galaxy/util/compression_utils.py
@@ -7,23 +7,20 @@ import os
import tarfile
import tempfile
import zipfile
+from collections.abc import (
+ Iterable,
+ Iterator,
+)
from types import TracebackType
from typing import (
Any,
cast,
IO,
- Iterable,
- Iterator,
- List,
- Optional,
+ Literal,
overload,
- Tuple,
- Type,
- Union,
)
from typing_extensions import (
- Literal,
Self,
)
@@ -45,20 +42,18 @@ except ImportError:
log = logging.getLogger(__name__)
-FileObjTypeStr = Union[IO[str], io.TextIOWrapper]
-FileObjTypeBytes = Union[gzip.GzipFile, bz2.BZ2File, lzma.LZMAFile, IO[bytes]]
-FileObjType = Union[FileObjTypeStr, FileObjTypeBytes]
+FileObjTypeStr = IO[str] | io.TextIOWrapper
+FileObjTypeBytes = gzip.GzipFile | bz2.BZ2File | lzma.LZMAFile | IO[bytes]
+FileObjType = FileObjTypeStr | FileObjTypeBytes
+
+
+@overload
+def get_fileobj(filename: str, mode: Literal["r"], compressed_formats: list[str] | None = None) -> FileObjTypeStr: ...
@overload
def get_fileobj(
- filename: str, mode: Literal["r"], compressed_formats: Optional[List[str]] = None
-) -> FileObjTypeStr: ...
-
-
-@overload
-def get_fileobj(
- filename: str, mode: Literal["rb"], compressed_formats: Optional[List[str]] = None
+ filename: str, mode: Literal["rb"], compressed_formats: list[str] | None = None
) -> FileObjTypeBytes: ...
@@ -67,10 +62,10 @@ def get_fileobj(filename: str) -> FileObjTypeStr: ...
@overload
-def get_fileobj(filename: str, mode: str = "r", compressed_formats: Optional[List[str]] = None) -> FileObjType: ...
+def get_fileobj(filename: str, mode: str = "r", compressed_formats: list[str] | None = None) -> FileObjType: ...
-def get_fileobj(filename: str, mode: str = "r", compressed_formats: Optional[List[str]] = None) -> FileObjType:
+def get_fileobj(filename: str, mode: str = "r", compressed_formats: list[str] | None = None) -> FileObjType:
"""
Returns a fileobj. If the file is compressed, return an appropriate file
reader. In text mode, always use 'utf-8' encoding.
@@ -85,29 +80,29 @@ def get_fileobj(filename: str, mode: str = "r", compressed_formats: Optional[Lis
@overload
def get_fileobj_raw(
- filename: str, mode: Literal["r"], compressed_formats: Optional[List[str]] = None
-) -> Tuple[Optional[str], FileObjTypeStr]: ...
+ filename: str, mode: Literal["r"], compressed_formats: list[str] | None = None
+) -> tuple[str | None, FileObjTypeStr]: ...
@overload
def get_fileobj_raw(
- filename: str, mode: Literal["rb"], compressed_formats: Optional[List[str]] = None
-) -> Tuple[Optional[str], FileObjTypeBytes]: ...
+ filename: str, mode: Literal["rb"], compressed_formats: list[str] | None = None
+) -> tuple[str | None, FileObjTypeBytes]: ...
@overload
-def get_fileobj_raw(filename: str) -> Tuple[Optional[str], FileObjTypeStr]: ...
+def get_fileobj_raw(filename: str) -> tuple[str | None, FileObjTypeStr]: ...
@overload
def get_fileobj_raw(
- filename: str, mode: str = "r", compressed_formats: Optional[List[str]] = None
-) -> Tuple[Optional[str], FileObjType]: ...
+ filename: str, mode: str = "r", compressed_formats: list[str] | None = None
+) -> tuple[str | None, FileObjType]: ...
def get_fileobj_raw(
- filename: str, mode: str = "r", compressed_formats: Optional[List[str]] = None
-) -> Tuple[Optional[str], FileObjType]:
+ filename: str, mode: str = "r", compressed_formats: list[str] | None = None
+) -> tuple[str | None, FileObjType]:
if compressed_formats is None:
compressed_formats = ["bz2", "gzip", "xz", "zip"]
# Remove 't' from mode, which may cause an error for compressed files
@@ -117,7 +112,7 @@ def get_fileobj_raw(
mode = "r"
compressed_format = None
if "gzip" in compressed_formats and is_gzip(filename):
- fh: Union[gzip.GzipFile, bz2.BZ2File, lzma.LZMAFile, IO[bytes]] = gzip.GzipFile(filename, mode)
+ fh: gzip.GzipFile | bz2.BZ2File | lzma.LZMAFile | IO[bytes] = gzip.GzipFile(filename, mode)
compressed_format = "gzip"
elif "bz2" in compressed_formats and is_bz2(filename):
mode = cast(Literal["a", "ab", "r", "rb", "w", "wb", "x", "xb"], mode)
@@ -147,7 +142,7 @@ def get_fileobj_raw(
return compressed_format, fh
-def file_iter(fname: str, sep: Optional[Any] = None) -> Iterator[List[str]]:
+def file_iter(fname: str, sep: Any | None = None) -> Iterator[list[str]]:
"""
This generator iterates over a file and yields its lines
splitted via the C{sep} parameter. Skips empty lines and lines starting with
@@ -163,7 +158,7 @@ def file_iter(fname: str, sep: Optional[Any] = None) -> Iterator[List[str]]:
yield line.split(sep)
-ArchiveMemberType = Union[tarfile.TarInfo, zipfile.ZipInfo]
+ArchiveMemberType = tarfile.TarInfo | zipfile.ZipInfo
def decompress_bytes_to_directory(content: bytes) -> str:
@@ -184,7 +179,7 @@ def decompress_path_to_directory(path: str) -> str:
class CompressedFile:
- archive: Union[tarfile.TarFile, zipfile.ZipFile]
+ archive: tarfile.TarFile | zipfile.ZipFile
@staticmethod
def can_decompress(file_path: StrPath) -> bool:
@@ -281,7 +276,7 @@ class CompressedFile:
)
return os.path.abspath(os.path.join(extraction_path, common_prefix_dir))
- def safemembers(self) -> Union[Iterable[tarfile.TarInfo], Iterable[str]]:
+ def safemembers(self) -> Iterable[tarfile.TarInfo] | Iterable[str]:
members = self.archive
common_prefix_dir = self.common_prefix_dir
if self.file_type == "tar":
@@ -301,11 +296,11 @@ class CompressedFile:
raise Exception(f"{name} is blocked (illegal path).")
yield name
- def getmembers_tar(self) -> List[tarfile.TarInfo]:
+ def getmembers_tar(self) -> list[tarfile.TarInfo]:
assert isinstance(self.archive, tarfile.TarFile)
return self.archive.getmembers()
- def getmembers_zip(self) -> List[zipfile.ZipInfo]:
+ def getmembers_zip(self) -> list[zipfile.ZipInfo]:
assert isinstance(self.archive, zipfile.ZipFile)
return self.archive.infolist()
@@ -315,14 +310,14 @@ class CompressedFile:
def getname_zip(self, item: zipfile.ZipInfo) -> str:
return item.filename
- def getmember(self, name: str) -> Optional[ArchiveMemberType]:
+ def getmember(self, name: str) -> ArchiveMemberType | None:
for member in self.getmembers():
if self.getname(member) == name:
return member
return None
- def getmembers(self) -> List[ArchiveMemberType]:
- return cast(List[ArchiveMemberType], getattr(self, f"getmembers_{self.type}")())
+ def getmembers(self) -> list[ArchiveMemberType]:
+ return cast(list[ArchiveMemberType], getattr(self, f"getmembers_{self.type}")())
def getname(self, member: ArchiveMemberType) -> str:
return cast(str, getattr(self, f"getname_{self.type}")(member))
@@ -344,7 +339,7 @@ class CompressedFile:
return False
@staticmethod
- def open_tar(file: Union[StrPath, IO[bytes]], mode: Literal["a", "r", "w", "x"] = "r") -> tarfile.TarFile:
+ def open_tar(file: StrPath | IO[bytes], mode: Literal["a", "r", "w", "x"] = "r") -> tarfile.TarFile:
if isinstance(file, (str, os.PathLike)):
tf = tarfile.open(file, mode=mode, errorlevel=0)
else:
@@ -356,7 +351,7 @@ class CompressedFile:
return tf
@staticmethod
- def open_zip(file: Union[StrPath, IO[bytes]], mode: Literal["a", "r", "w", "x"] = "r") -> zipfile.ZipFile:
+ def open_zip(file: StrPath | IO[bytes], mode: Literal["a", "r", "w", "x"] = "r") -> zipfile.ZipFile:
return zipfile.ZipFile(file, mode)
@staticmethod
@@ -379,9 +374,9 @@ class CompressedFile:
def __exit__(
self,
- exc_type: Optional[Type[BaseException]],
- exc_value: Optional[BaseException],
- traceback: Optional[TracebackType],
+ exc_type: type[BaseException] | None,
+ exc_value: BaseException | None,
+ traceback: TracebackType | None,
) -> bool:
try:
self.archive.close()
@@ -410,10 +405,10 @@ def make_fast_zipfile(
base_dir: StrPath,
verbose: int = 0,
dry_run: int = 0,
- logger: Optional[logging.Logger] = None,
- owner: Optional[str] = None,
- group: Optional[str] = None,
- root_dir: Optional[StrPath] = None,
+ logger: logging.Logger | None = None,
+ owner: str | None = None,
+ group: str | None = None,
+ root_dir: StrPath | None = None,
) -> str:
"""Create a zip file from all the files under 'base_dir'.
diff --git a/lib/galaxy/util/config_parsers.py b/lib/galaxy/util/config_parsers.py
index 7863d66d08f..6f8f091b259 100644
--- a/lib/galaxy/util/config_parsers.py
+++ b/lib/galaxy/util/config_parsers.py
@@ -1,17 +1,13 @@
import ipaddress
-from typing import (
- List,
- Union,
-)
from galaxy.util import unicodify
-IpAddressT = Union[ipaddress.IPv4Address, ipaddress.IPv6Address]
-IpNetworkT = Union[ipaddress.IPv4Network, ipaddress.IPv6Network]
-IpAllowedListEntryT = Union[IpAddressT, IpNetworkT]
+IpAddressT = ipaddress.IPv4Address | ipaddress.IPv6Address
+IpNetworkT = ipaddress.IPv4Network | ipaddress.IPv6Network
+IpAllowedListEntryT = IpAddressT | IpNetworkT
-def parse_allowlist_ips(fetch_url_allowlist: List[str]) -> List[IpAllowedListEntryT]:
+def parse_allowlist_ips(fetch_url_allowlist: list[str]) -> list[IpAllowedListEntryT]:
return [
(
ipaddress.ip_network(unicodify(ip.strip())) # If it has a slash, assume 127.0.0.1/24 notation
diff --git a/lib/galaxy/util/config_templates.py b/lib/galaxy/util/config_templates.py
index 6305453b16d..e02b05d895e 100644
--- a/lib/galaxy/util/config_templates.py
+++ b/lib/galaxy/util/config_templates.py
@@ -5,19 +5,18 @@ This is capturing code shared by file source templates and object store template
import logging
import os
-from collections.abc import Iterable
-from typing import (
- Any,
+from collections.abc import (
Callable,
- cast,
- Dict,
- List,
- Optional,
+ Iterable,
Sequence,
- Tuple,
- Type,
+)
+from typing import (
+ Annotated,
+ Any,
+ cast,
+ Literal,
+ Optional,
TypeVar,
- Union,
)
from urllib.parse import urlencode
@@ -33,8 +32,6 @@ from pydantic import (
)
from pydantic.fields import FieldInfo
from typing_extensions import (
- Annotated,
- Literal,
NotRequired,
Protocol,
TypedDict,
@@ -62,14 +59,14 @@ from galaxy.util import asbool
log = logging.getLogger(__name__)
TemplateVariableType = Literal["string", "path_component", "boolean", "integer"]
-TemplateVariableValueType = Union[str, bool, int]
+TemplateVariableValueType = str | bool | int
TemplateExpansion = str
MarkdownContent = str
-RawTemplateConfig = Dict[str, Any]
-UserDetailsDict = Dict[str, Any]
-VariablesDict = Dict[str, TemplateVariableValueType]
-SecretsDict = Dict[str, str]
-EnvironmentDict = Dict[str, str]
+RawTemplateConfig = dict[str, Any]
+UserDetailsDict = dict[str, Any]
+VariablesDict = dict[str, TemplateVariableValueType]
+SecretsDict = dict[str, str]
+EnvironmentDict = dict[str, str]
class StrictModel(BaseModel):
@@ -78,63 +75,63 @@ class StrictModel(BaseModel):
class BaseTemplateVariable(StrictModel):
name: str
- label: Optional[str] = None
- help: Optional[MarkdownContent] = None
- optional: Optional[bool] = None
- multiline: Optional[bool] = None
- validators: Optional[Sequence[AnySafeValidatorModel]] = None
+ label: str | None = None
+ help: MarkdownContent | None = None
+ optional: bool | None = None
+ multiline: bool | None = None
+ validators: Sequence[AnySafeValidatorModel] | None = None
class TemplateVariableString(BaseTemplateVariable):
type: Literal["string"]
- default: Optional[str] = None
+ default: str | None = None
class TemplateVariableInteger(BaseTemplateVariable):
type: Literal["integer"]
- default: Optional[int] = None
+ default: int | None = None
# add min/max
class TemplateVariablePathComponent(BaseTemplateVariable):
type: Literal["path_component"]
- default: Optional[str] = None
+ default: str | None = None
class TemplateVariableBoolean(BaseTemplateVariable):
type: Literal["boolean"]
- default: Optional[bool] = None
+ default: bool | None = None
-TemplateVariable = Union[
- TemplateVariableString, TemplateVariableInteger, TemplateVariablePathComponent, TemplateVariableBoolean
-]
+TemplateVariable = (
+ TemplateVariableString | TemplateVariableInteger | TemplateVariablePathComponent | TemplateVariableBoolean
+)
class TemplateSecret(StrictModel):
name: str
- label: Optional[str] = None
- help: Optional[MarkdownContent] = None
- optional: Optional[bool] = None
- multiline: Optional[bool] = None
+ label: str | None = None
+ help: MarkdownContent | None = None
+ optional: bool | None = None
+ multiline: bool | None = None
class TemplateEnvironmentSecret(StrictModel):
type: Literal["secret"]
name: str
vault_key: str
- default: Optional[str] = None
+ default: str | None = None
class TemplateEnvironmentVariable(StrictModel):
type: Literal["variable"]
name: str
variable: str
- default: Optional[str] = None
+ default: str | None = None
-TemplateEnvironmentEntry = Union[TemplateEnvironmentVariable, TemplateEnvironmentSecret]
-TemplateEnvironment = RootModel[List[TemplateEnvironmentEntry]]
+TemplateEnvironmentEntry = TemplateEnvironmentVariable | TemplateEnvironmentSecret
+TemplateEnvironment = RootModel[list[TemplateEnvironmentEntry]]
def _ensure_path_component(input: Any):
@@ -157,26 +154,25 @@ def _environment(template_start: str, template_end: str) -> NativeEnvironment:
class TemplateConfiguration(Protocol):
-
- def model_dump(self) -> Dict[str, Any]:
+ def model_dump(self) -> dict[str, Any]:
"""Implements a pydantic model dump to build simple JSON dictionary."""
@property
- def template_start(self) -> Optional[str]:
+ def template_start(self) -> str | None:
"""Set a custom variable start for Jinja variable substitution.
https://stackoverflow.com/questions/12083319/add-custom-tokens-in-jinja2-e-g-somevar
"""
@property
- def template_end(self) -> Optional[str]:
+ def template_end(self) -> str | None:
"""Set a custom variable end for Jinja variable substitution.
https://stackoverflow.com/questions/12083319/add-custom-tokens-in-jinja2-e-g-somevar
"""
-def populate_default_variables(variables: Optional[List[TemplateVariable]], variable_values: VariablesDict):
+def populate_default_variables(variables: list[TemplateVariable] | None, variable_values: VariablesDict):
if variables:
for variable in variables:
name = variable.name
@@ -203,7 +199,7 @@ def expand_raw_config(
def _expand_raw_config(
- template_configuration: TemplateConfiguration, template_variables: Dict[str, Any]
+ template_configuration: TemplateConfiguration, template_variables: dict[str, Any]
) -> RawTemplateConfig:
template_start = template_configuration.template_start or "{{"
template_end = template_configuration.template_end or "}}"
@@ -255,7 +251,7 @@ def _clean_template_meta_parameters(config: RawTemplateConfig) -> RawTemplateCon
# cwl-like - convert simple dictionary to list of dictionaries for quickly
# configuring variables and secrets
-def apply_syntactic_sugar(raw_templates: List[RawTemplateConfig]) -> List[RawTemplateConfig]:
+def apply_syntactic_sugar(raw_templates: list[RawTemplateConfig]) -> list[RawTemplateConfig]:
templates = []
expanded_raw_templates = _expand_includes(raw_templates)
for template in expanded_raw_templates:
@@ -266,14 +262,14 @@ def apply_syntactic_sugar(raw_templates: List[RawTemplateConfig]) -> List[RawTem
return templates
-def _expand_includes(raw_templates: List[RawTemplateConfig]) -> List[RawTemplateConfig]:
+def _expand_includes(raw_templates: list[RawTemplateConfig]) -> list[RawTemplateConfig]:
expanded_raw_templates = []
for raw_template in raw_templates:
expanded_raw_templates.extend(_expand_include(raw_template))
return expanded_raw_templates
-def _expand_include(raw_template: RawTemplateConfig) -> List[RawTemplateConfig]:
+def _expand_include(raw_template: RawTemplateConfig) -> list[RawTemplateConfig]:
has_one_key = len(raw_template.keys()) == 1
has_include = "include" in raw_template
@@ -281,7 +277,7 @@ def _expand_include(raw_template: RawTemplateConfig) -> List[RawTemplateConfig]:
include = raw_template["include"]
with open(include) as f:
included = yaml.safe_load(f)
- raw_templates: List[RawTemplateConfig]
+ raw_templates: list[RawTemplateConfig]
if isinstance(included, list):
raw_templates = included
else:
@@ -307,7 +303,7 @@ class TemplateReference(Protocol):
class InstanceDefinition(TemplateReference, Protocol):
- variables: Dict[str, Any]
+ variables: dict[str, Any]
secrets: SecretsDict
@@ -322,25 +318,25 @@ class Template(Protocol):
def type(self) -> str: ...
@property
- def variables(self) -> Optional[List[TemplateVariable]]: ...
+ def variables(self) -> list[TemplateVariable] | None: ...
@property
- def secrets(self) -> Optional[List[TemplateSecret]]: ...
+ def secrets(self) -> list[TemplateSecret] | None: ...
@property
- def environment(self) -> Optional[List[TemplateEnvironmentEntry]]: ...
+ def environment(self) -> list[TemplateEnvironmentEntry] | None: ...
T = TypeVar("T", bound=Template, covariant=True)
-def find_template(templates: List[T], instance_reference: TemplateReference, what: str) -> T:
+def find_template(templates: list[T], instance_reference: TemplateReference, what: str) -> T:
template_id = instance_reference.template_id
template_version = instance_reference.template_version
return find_template_by(templates, template_id, template_version, what)
-def find_template_by(templates: List[T], template_id: str, template_version: int, what: str) -> T:
+def find_template_by(templates: list[T], template_id: str, template_version: int, what: str) -> T:
for template in templates:
if template.id == template_id and template.version == template_version:
return template
@@ -390,7 +386,7 @@ def validate_specified_datatypes(instance: InstanceDefinition, template: Templat
validate_specified_datatypes_variables(variables, template)
-def validate_specified_datatypes_variables(variables: Dict[str, Any], template: Template):
+def validate_specified_datatypes_variables(variables: dict[str, Any], template: Template):
for template_variable in template.variables or []:
name = template_variable.name
# Only fall back to default for optional variables
@@ -431,14 +427,14 @@ def validate_specified_datatypes_variables(variables: Dict[str, Any], template:
_run_variable_validator(validator, variable_value, name)
-def validate_no_extra_secrets_defined(secrets: Dict[str, str], template: Template) -> None:
+def validate_no_extra_secrets_defined(secrets: dict[str, str], template: Template) -> None:
template_secrets = secrets_as_dict(template.secrets)
for secret in secrets.keys():
if secret not in template_secrets:
raise RequestParameterInvalidException(f"No secret named {secret} for this template")
-def validate_no_extra_variables_defined(variables: Dict[str, Any], template: Template):
+def validate_no_extra_variables_defined(variables: dict[str, Any], template: Template):
template_variables = _variables_as_dict(template.variables)
for variable in variables.keys():
if variable not in template_variables:
@@ -453,21 +449,21 @@ def validate_secrets_and_variables(instance: InstanceDefinition, template: Templ
validate_no_extra_variables_defined(instance.variables, template)
-def secrets_as_dict(secrets: Optional[List[TemplateSecret]]) -> Dict[str, TemplateSecret]:
+def secrets_as_dict(secrets: list[TemplateSecret] | None) -> dict[str, TemplateSecret]:
as_dict = {}
for secret in secrets or []:
as_dict[secret.name] = secret
return as_dict
-def _variables_as_dict(variables: Optional[List[TemplateVariable]]) -> Dict[str, TemplateVariable]:
+def _variables_as_dict(variables: list[TemplateVariable] | None) -> dict[str, TemplateVariable]:
as_dict = {}
for variable in variables or []:
as_dict[variable.name] = variable
return as_dict
-def _is_of_exact_type(object: Any, target_type: Type):
+def _is_of_exact_type(object: Any, target_type: type):
# isinstance(False, int) and False == 0 are both True in Python...
# We are creating a DSL here that is intentionally more strict than Python
# so we are using type() instead of isinstance and we have the test coverage
@@ -502,8 +498,8 @@ class PluginAspectStatus(StrictModel):
class PluginStatus(StrictModel):
template_definition: PluginAspectStatus
- template_settings: Optional[PluginAspectStatus] = None
- connection: Optional[PluginAspectStatus] = None
+ template_settings: PluginAspectStatus | None = None
+ connection: PluginAspectStatus | None = None
# I would love to disambiguate connection vs auth errors but would
# attempting to do that cause confusion. Maybe not if the user interface
# skipped presenting the one that couldn't be disambiguated for that
@@ -511,10 +507,10 @@ class PluginStatus(StrictModel):
# TODO: Fill in writable checks.
# writable: Optional[PluginAspectStatus] = None
- oauth2_access_token_generation: Optional[PluginAspectStatus] = None
+ oauth2_access_token_generation: PluginAspectStatus | None = None
-def status_template_definition(template: Optional[Template]) -> PluginAspectStatus:
+def status_template_definition(template: Template | None) -> PluginAspectStatus:
# if we found a template in the catalog, it was validated at load time. Reflect
# this as a PluginAspectStatus
if template:
@@ -523,7 +519,7 @@ def status_template_definition(template: Optional[Template]) -> PluginAspectStat
return PluginAspectStatus(state="not_ok", message="Template not found or not loaded")
-def settings_exception_to_status(exception: Optional[Exception]) -> PluginAspectStatus:
+def settings_exception_to_status(exception: Exception | None) -> PluginAspectStatus:
if exception is None:
status = PluginAspectStatus(state="ok", message="Valid configuration resulted from supplied settings")
elif isinstance(exception, UndefinedError):
@@ -538,7 +534,7 @@ def settings_exception_to_status(exception: Optional[Exception]) -> PluginAspect
return status
-def connection_exception_to_status(what: str, exception: Optional[Exception]) -> PluginAspectStatus:
+def connection_exception_to_status(what: str, exception: Exception | None) -> PluginAspectStatus:
if exception is None:
connection_status = PluginAspectStatus(state="ok", message="Valid connection resulted from supplied settings")
else:
@@ -554,11 +550,11 @@ class OAuth2Info(StrictModel):
class OAuth2Configuration(StrictModel):
authorize_url: str
token_url: str
- authorize_params: Optional[Dict[str, str]]
- scope: Optional[str] = None
+ authorize_params: dict[str, str] | None
+ scope: str | None = None
-ConfiguredOAuth2Sources = Dict[str, OAuth2Configuration]
+ConfiguredOAuth2Sources = dict[str, OAuth2Configuration]
class OAuth2ClientPair(StrictModel):
@@ -567,11 +563,11 @@ class OAuth2ClientPair(StrictModel):
def get_authorize_url(
- client_id_or_pair: Union[str, OAuth2ClientPair],
+ client_id_or_pair: str | OAuth2ClientPair,
config: OAuth2Configuration,
- redirect_uri: Optional[str],
- state: Optional[str] = None,
- scope: Optional[str] = None,
+ redirect_uri: str | None,
+ state: str | None = None,
+ scope: str | None = None,
) -> str:
client_id = client_id_or_pair if isinstance(client_id_or_pair, str) else client_id_or_pair.client_id
query_data = dict(
@@ -592,7 +588,7 @@ def get_authorize_url(
def get_token_from_code_raw(
- code: str, client_pair: OAuth2ClientPair, config: OAuth2Configuration, redirect_uri: Optional[str]
+ code: str, client_pair: OAuth2ClientPair, config: OAuth2Configuration, redirect_uri: str | None
) -> requests.Response:
data = {
"code": code,
@@ -630,7 +626,7 @@ def read_oauth2_info_from_configuration(
template_configuration: TemplateConfiguration,
user_details: UserDetailsDict,
environment: EnvironmentDict,
-) -> Tuple[OAuth2ClientPair, Optional[str]]:
+) -> tuple[OAuth2ClientPair, str | None]:
template_variables = {
"user": user_details,
"environment": environment,
@@ -639,7 +635,7 @@ def read_oauth2_info_from_configuration(
expanded_config = _expand_raw_config(template_configuration, template_variables)
oauth2_client_id = expanded_config["oauth2_client_id"]
oauth2_client_secret = expanded_config["oauth2_client_secret"]
- oauth2_scope = cast(Optional[str], expanded_config.get("oauth2_scope"))
+ oauth2_scope = cast(str | None, expanded_config.get("oauth2_scope"))
client_pair = OAuth2ClientPair(client_id=oauth2_client_id, client_secret=oauth2_client_secret)
return client_pair, oauth2_scope
@@ -659,12 +655,12 @@ def _make_field_optional(field_info: FieldInfo):
annotation = field_info.annotation
assert annotation is not None
if field_info.is_required():
- return Annotated[Union[annotation, None], field_info], None
+ return Annotated[annotation | None, field_info], None
else:
return Annotated[annotation, field_info]
-def make_model_with_all_fields_optional(model: Type[M], fields=None) -> Type[M]:
+def make_model_with_all_fields_optional(model: type[M], fields=None) -> type[M]:
"""Returns a new Pydantic model based on `model`, but with all fields optional."""
if fields is None:
fields = model.model_fields.items()
@@ -679,15 +675,13 @@ def make_model_with_all_fields_optional(model: Type[M], fields=None) -> Type[M]:
# TODO: This is a workaround to make all fields optional.
# It should be removed when Python/pydantic supports this feature natively.
# https://github.com/pydantic/pydantic/issues/1673
-def partial_model(
- include: Optional[List[str]] = None, exclude: Optional[List[str]] = None
-) -> Callable[[Type[M]], Type[M]]:
+def partial_model(include: list[str] | None = None, exclude: list[str] | None = None) -> Callable[[type[M]], type[M]]:
"""Decorator to make all model fields optional"""
if exclude is None:
exclude = []
- def decorator(model: Type[M]) -> Type[M]:
+ def decorator(model: type[M]) -> type[M]:
if include is None:
fields: Iterable[tuple[str, FieldInfo]] = model.model_fields.items()
else:
diff --git a/lib/galaxy/util/custom_logging/__init__.py b/lib/galaxy/util/custom_logging/__init__.py
index 44f849c8320..6c834fb91bd 100644
--- a/lib/galaxy/util/custom_logging/__init__.py
+++ b/lib/galaxy/util/custom_logging/__init__.py
@@ -2,7 +2,6 @@ import logging
from typing import (
Any,
cast,
- Optional,
)
@@ -18,6 +17,6 @@ logging.addLevelName(LOGLV_TRACE, "TRACE")
logging.setLoggerClass(GalaxyLogger)
-def get_logger(name: Optional[str] = None) -> GalaxyLogger:
+def get_logger(name: str | None = None) -> GalaxyLogger:
logger = logging.getLogger(name)
return cast(GalaxyLogger, logger)
diff --git a/lib/galaxy/util/dictifiable.py b/lib/galaxy/util/dictifiable.py
index d40c7f8f1f9..8a1f833c339 100644
--- a/lib/galaxy/util/dictifiable.py
+++ b/lib/galaxy/util/dictifiable.py
@@ -1,13 +1,11 @@
import datetime
import uuid
+from collections.abc import Callable
from typing import (
Any,
- Callable,
- Dict,
- Optional,
)
-ValueMapperT = Dict[str, Callable]
+ValueMapperT = dict[str, Callable]
def dict_for(obj, **kwds):
@@ -24,9 +22,7 @@ class UsesDictVisibleKeys:
to_dict with whatever signature makes sense for the class.
"""
- def _dictify_view_keys(
- self, view: str = "collection", value_mapper: Optional[ValueMapperT] = None
- ) -> Dict[str, Any]:
+ def _dictify_view_keys(self, view: str = "collection", value_mapper: ValueMapperT | None = None) -> dict[str, Any]:
"""
Return item dictionary.
"""
@@ -85,7 +81,7 @@ class Dictifiable(UsesDictVisibleKeys):
when for sharing objects across boundaries, such as the API, tool scripts,
and JavaScript code."""
- def to_dict(self, view: str = "collection", value_mapper: Optional[ValueMapperT] = None) -> Dict[str, Any]:
+ def to_dict(self, view: str = "collection", value_mapper: ValueMapperT | None = None) -> dict[str, Any]:
"""
Return item dictionary.
"""
diff --git a/lib/galaxy/util/hash_util.py b/lib/galaxy/util/hash_util.py
index 1bcc5d36d94..bf30e504c0f 100644
--- a/lib/galaxy/util/hash_util.py
+++ b/lib/galaxy/util/hash_util.py
@@ -6,16 +6,11 @@ introduced hashlib which replaced sha in Python 2.4 and previous versions.
import hashlib
import hmac
import logging
+from collections.abc import Callable
from enum import Enum
from typing import (
Any,
- Callable,
- Dict,
- List,
Literal,
- Optional,
- Tuple,
- Union,
)
from . import smart_str
@@ -48,22 +43,22 @@ class HashFunctionNameEnum(str, Enum):
HashFunctionNames = Literal["MD5", "SHA-1", "SHA-256", "SHA-512"]
-HASH_NAME_ALIAS: Dict[str, str] = {
+HASH_NAME_ALIAS: dict[str, str] = {
"SHA1": "SHA-1",
"SHA256": "SHA-256",
"SHA512": "SHA-512",
}
-HASH_NAME_MAP: Dict[HashFunctionNameEnum, HashFunctionT] = {
+HASH_NAME_MAP: dict[HashFunctionNameEnum, HashFunctionT] = {
HashFunctionNameEnum.md5: md5,
HashFunctionNameEnum.sha1: sha1,
HashFunctionNameEnum.sha256: sha256,
HashFunctionNameEnum.sha512: sha512,
}
-HASH_NAMES: List[HashFunctionNameEnum] = list(HASH_NAME_MAP.keys())
+HASH_NAMES: list[HashFunctionNameEnum] = list(HASH_NAME_MAP.keys())
-def as_hash_function_name(hash_name: str) -> Optional[HashFunctionNames]:
+def as_hash_function_name(hash_name: str) -> HashFunctionNames | None:
"""Convert a hash name string to a HashFunctionName.
Considering possible aliases and returning None if the name is not recognized."""
@@ -76,9 +71,9 @@ def as_hash_function_name(hash_name: str) -> Optional[HashFunctionNames]:
def memory_bound_hexdigest(
- hash_func: Optional[HashFunctionT] = None,
- hash_func_name: Optional[HashFunctionNameEnum] = None,
- path: Optional[str] = None,
+ hash_func: HashFunctionT | None = None,
+ hash_func_name: HashFunctionNameEnum | None = None,
+ path: str | None = None,
file=None,
):
if hash_func is None:
@@ -100,7 +95,7 @@ def memory_bound_hexdigest(
file.close()
-def md5_hash_file(path: StrPath) -> Optional[str]:
+def md5_hash_file(path: StrPath) -> str | None:
"""
Return a md5 hashdigest for a file or None if path could not be read.
"""
@@ -124,7 +119,7 @@ def md5_hash_str(s):
return m.hexdigest()
-def new_secure_hash_v2(text_type: Union[bytes, str]) -> str:
+def new_secure_hash_v2(text_type: bytes | str) -> str:
"""More modern version of new_secure_hash.
Certain passwords are set via new_insecure_hash (previously new_secure_hash),
@@ -134,7 +129,7 @@ def new_secure_hash_v2(text_type: Union[bytes, str]) -> str:
return sha512(smart_str(text_type)).hexdigest()
-def new_insecure_hash(text_type: Union[bytes, str]) -> str:
+def new_insecure_hash(text_type: bytes | str) -> str:
"""Returns the hexdigest of the sha1 hash of the argument `text_type`.
Previously called new_secure_hash, but this should not be considered
@@ -148,7 +143,7 @@ def new_insecure_hash(text_type: Union[bytes, str]) -> str:
return sha1(smart_str(text_type)).hexdigest()
-def hmac_new(key: Union[bytes, str], value: Union[bytes, str]) -> str:
+def hmac_new(key: bytes | str, value: bytes | str) -> str:
return hmac.new(smart_str(key), smart_str(value), sha).hexdigest()
@@ -160,7 +155,7 @@ def is_hashable(value: Any) -> bool:
return True
-def parse_checksum_hash(checksum: str) -> Tuple[HashFunctionNameEnum, str]:
+def parse_checksum_hash(checksum: str) -> tuple[HashFunctionNameEnum, str]:
"""Parses checksum strings in the form of `hash_type$hash_value` considering possible aliases."""
hash_name, hash_value = checksum.split("$", 1)
hash_name = hash_name.upper()
diff --git a/lib/galaxy/util/heartbeat.py b/lib/galaxy/util/heartbeat.py
index 520ddde1234..1b36ea545b4 100644
--- a/lib/galaxy/util/heartbeat.py
+++ b/lib/galaxy/util/heartbeat.py
@@ -3,7 +3,6 @@ import sys
import threading
import time
import traceback
-from typing import Dict
def get_current_thread_object_dict():
@@ -43,7 +42,7 @@ class Heartbeat(threading.Thread):
self.fname_nonsleeping = None
self.file_nonsleeping = None
self.pid = None
- self.nonsleeping_heartbeats: Dict[int, int] = {}
+ self.nonsleeping_heartbeats: dict[int, int] = {}
# Event to wait on when sleeping, allows us to interrupt for shutdown
self.wait_event = threading.Event()
diff --git a/lib/galaxy/util/image_util.py b/lib/galaxy/util/image_util.py
index b8c26cf0ff5..ef69e1b0951 100644
--- a/lib/galaxy/util/image_util.py
+++ b/lib/galaxy/util/image_util.py
@@ -1,10 +1,6 @@
"""Provides utilities for working with image files."""
import logging
-from typing import (
- List,
- Optional,
-)
try:
from PIL import Image
@@ -14,7 +10,7 @@ except ImportError:
log = logging.getLogger(__name__)
-def image_type(filename: str) -> Optional[str]:
+def image_type(filename: str) -> str | None:
fmt = None
if Image is not None:
try:
@@ -28,7 +24,7 @@ def image_type(filename: str) -> Optional[str]:
return None
-def check_image_type(filename: str, types: List[str]) -> bool:
+def check_image_type(filename: str, types: list[str]) -> bool:
fmt = image_type(filename)
if fmt in types:
return True
diff --git a/lib/galaxy/util/json.py b/lib/galaxy/util/json.py
index 1b3d03f6c47..78d8cb20817 100644
--- a/lib/galaxy/util/json.py
+++ b/lib/galaxy/util/json.py
@@ -110,7 +110,7 @@ def validate_jsonrpc_request(request, regular_methods, notification_methods):
), 'This server requires JSON-RPC 2.0 and no "jsonrpc" member was sent with the Request object as per the JSON-RPC 2.0 Specification.'
assert (
request["jsonrpc"] == "2.0"
- ), f"Requested JSON-RPC version \"{request['jsonrpc']}\" != required version \"2.0\"."
+ ), f'Requested JSON-RPC version "{request["jsonrpc"]}" != required version "2.0".'
assert "method" in request, 'No "method" member was sent with the Request object'
except AssertionError as e:
return (
@@ -137,7 +137,7 @@ def validate_jsonrpc_request(request, regular_methods, notification_methods):
if request["method"] in regular_methods:
assert (
"id" in request
- ), f"No \"id\" member was sent with the Request object and the requested method \"{request['method']}\" is not a notification method"
+ ), f'No "id" member was sent with the Request object and the requested method "{request["method"]}" is not a notification method'
except AssertionError as e:
return (
False,
@@ -174,7 +174,7 @@ def validate_jsonrpc_response(response, id=None):
try:
assert "id" in response and response["id"] == id
except Exception:
- log.error(f"The response id \"{response['id']}\" does not match the request id \"{id}\"")
+ log.error(f'The response id "{response["id"]}" does not match the request id "{id}"')
return False, response
return True, response
diff --git a/lib/galaxy/util/odict.py b/lib/galaxy/util/odict.py
index 9094464a299..aa1ab9ab041 100644
--- a/lib/galaxy/util/odict.py
+++ b/lib/galaxy/util/odict.py
@@ -8,16 +8,9 @@ Whenever possible the stdlib `collections.OrderedDict` should be used instead of
this custom implementation.
"""
-import sys
from collections import UserDict
from typing import (
- Dict,
- Generic,
- List,
- Optional,
- Tuple,
TypeVar,
- Union,
)
dict_alias = dict
@@ -25,16 +18,9 @@ dict_alias = dict
KeyT = TypeVar("KeyT")
ValueT = TypeVar("ValueT")
-if sys.version_info >= (3, 9):
- # A simple type alias doesn't work with mypy
- class TypedUserDict(UserDict[KeyT, ValueT]): ...
-
-else:
-
- # UserDict is not generic in Python < 3.9
- # TypeError: 'ABCMeta' object is not subscriptable
- class TypedUserDict(UserDict, Generic[KeyT, ValueT]): ...
+# A simple type alias doesn't work with mypy
+class TypedUserDict(UserDict[KeyT, ValueT]): ...
class odict(TypedUserDict[KeyT, ValueT]):
@@ -46,9 +32,9 @@ class odict(TypedUserDict[KeyT, ValueT]):
order.
"""
- def __init__(self, dict: Optional[Union[Dict[KeyT, ValueT], List[Tuple[KeyT, ValueT]]]] = None) -> None:
+ def __init__(self, dict: dict[KeyT, ValueT] | list[tuple[KeyT, ValueT]] | None = None) -> None:
item = dict
- self._keys: List[KeyT] = []
+ self._keys: list[KeyT] = []
if isinstance(item, dict_alias):
super().__init__(item)
else:
@@ -81,7 +67,7 @@ class odict(TypedUserDict[KeyT, ValueT]):
def keys(self):
return self._keys[:]
- def popitem(self) -> Tuple[KeyT, ValueT]:
+ def popitem(self) -> tuple[KeyT, ValueT]:
try:
key = self._keys[-1]
except IndexError:
diff --git a/lib/galaxy/util/path/__init__.py b/lib/galaxy/util/path/__init__.py
index 447bfc3cb19..bfa2081863c 100644
--- a/lib/galaxy/util/path/__init__.py
+++ b/lib/galaxy/util/path/__init__.py
@@ -5,6 +5,7 @@ import importlib
import logging
import shlex
import types
+from collections.abc import Iterator
from functools import partial
from itertools import starmap
from operator import getitem
@@ -32,12 +33,7 @@ from os.path import (
from pathlib import Path
from typing import (
AnyStr,
- Iterator,
- List,
- Optional,
- Tuple,
TYPE_CHECKING,
- Union,
)
try:
@@ -54,24 +50,24 @@ import galaxy.util
# Stable in Python 3.10 path types
if TYPE_CHECKING:
- StrPath = Union[str, PathLike[str]]
- BytesPath = Union[bytes, PathLike[bytes]]
- GenericPath = Union[AnyStr, PathLike[AnyStr]]
- StrOrBytesPath = Union[str, bytes, PathLike[str], PathLike[bytes]]
+ StrPath = str | PathLike[str]
+ BytesPath = bytes | PathLike[bytes]
+ GenericPath = AnyStr | PathLike[AnyStr] # type: ignore[misc] # TypeVar in | expression confuses mypy
+ StrOrBytesPath = str | bytes | PathLike[str] | PathLike[bytes]
else:
- StrPath = Union[str, PathLike]
- BytesPath = Union[bytes, PathLike]
- GenericPath = Union[AnyStr, PathLike]
- StrOrBytesPath = Union[str, bytes, PathLike, PathLike]
+ StrPath = str | PathLike
+ BytesPath = bytes | PathLike
+ GenericPath = AnyStr | PathLike
+ StrOrBytesPath = str | bytes | PathLike | PathLike
-AllowListT = Optional[List[GenericPath]]
+AllowListT = list[GenericPath] | None # type: ignore[valid-type] # GenericPath is TypeVar-based, mypy can't resolve
WALK_MAX_DIRS = 10000
log = logging.getLogger(__name__)
-def safe_path(path: GenericPath, allowlist: AllowListT = None):
+def safe_path(path: GenericPath, allowlist: AllowListT = None): # type: ignore[valid-type] # GenericPath is TypeVar-based
"""Ensure that a the absolute location of the path (after following symlinks) is either itself or on the allowlist
of acceptable locations.
@@ -86,7 +82,7 @@ def safe_path(path: GenericPath, allowlist: AllowListT = None):
return any(__contains(dirname(path), path, allowlist=allowlist))
-def safe_contains(prefix: GenericPath, path: GenericPath, allowlist: AllowListT = None, real=None):
+def safe_contains(prefix: GenericPath, path: GenericPath, allowlist: AllowListT = None, real=None): # type: ignore[valid-type] # GenericPath is TypeVar-based
"""Ensure a path is contained within another path.
Given any two filesystem paths, ensure that ``path`` is contained in ``prefix``. If ``path`` exists (either as an
@@ -117,7 +113,7 @@ class _SafeContainsDirectoryChecker:
self.prefix = prefix
self.real_dirpath = realpath(join(prefix, dirpath))
- def check(self, filename: GenericPath) -> bool:
+ def check(self, filename: GenericPath) -> bool: # type: ignore[valid-type] # GenericPath is TypeVar-based
dirpath_path = join(self.real_dirpath, filename)
if islink(dirpath_path):
return safe_contains(self.prefix, filename, allowlist=self.allowlist)
@@ -125,7 +121,7 @@ class _SafeContainsDirectoryChecker:
return safe_contains(self.prefix, filename, allowlist=self.allowlist, real=dirpath_path)
-def safe_makedirs(path: GenericPath) -> None:
+def safe_makedirs(path: GenericPath) -> None: # type: ignore[valid-type] # GenericPath is TypeVar-based
"""Safely make a directory, do not fail if it already exists or is created during execution.
:type path: string
@@ -142,7 +138,7 @@ def safe_makedirs(path: GenericPath) -> None:
raise
-def safe_relpath(path: GenericPath) -> bool:
+def safe_relpath(path: GenericPath) -> bool: # type: ignore[valid-type] # GenericPath is TypeVar-based
"""Determine whether a relative path references a path outside its root.
This is a path computation: the filesystem is not accessed to confirm the existence or nature of ``path``.
@@ -198,7 +194,7 @@ def safe_walk(path, allowlist=None):
yield (dirpath, dirnames, filenames)
-def unsafe_walk(path: GenericPath, allowlist: AllowListT = None, username: Optional[str] = None):
+def unsafe_walk(path: GenericPath, allowlist: AllowListT = None, username: str | None = None): # type: ignore[valid-type] # GenericPath is TypeVar-based
"""Walk a path and ensure that none of its contents are symlinks outside the path.
It is assumed that ``path`` itself has already been validated e.g. with :func:`safe_relpath` or
@@ -222,7 +218,7 @@ def unsafe_walk(path: GenericPath, allowlist: AllowListT = None, username: Optio
return unsafe_paths
-def __path_permission_for_user(path: GenericPath, username: str) -> bool:
+def __path_permission_for_user(path: GenericPath, username: str) -> bool: # type: ignore[valid-type] # GenericPath is TypeVar-based
"""
:type path: string
:param path: a directory or file to check
@@ -395,7 +391,7 @@ def external_chown(path, pwent, external_chown_script, description="file"):
return False
-def __listify(item) -> Union[list, tuple]:
+def __listify(item) -> list | tuple:
"""A non-splitting version of :func:`galaxy.util.listify`."""
if not item:
return []
@@ -408,7 +404,7 @@ def __listify(item) -> Union[list, tuple]:
# helpers
-def __walk(path: GenericPath) -> Iterator[GenericPath]:
+def __walk(path: GenericPath) -> Iterator[GenericPath]: # type: ignore[valid-type] # GenericPath is TypeVar-based
for dirpath, dirnames, filenames in walk(path):
for name in dirnames:
yield join(dirpath, name)
@@ -416,9 +412,7 @@ def __walk(path: GenericPath) -> Iterator[GenericPath]:
yield join(dirpath, name)
-def __contains(
- prefix: GenericPath, path: GenericPath, allowlist: AllowListT = None, real: Optional[GenericPath] = None
-):
+def __contains(prefix: GenericPath, path: GenericPath, allowlist: AllowListT = None, real: GenericPath | None = None): # type: ignore[valid-type] # GenericPath is TypeVar-based
real = real or realpath(join(prefix, path))
yield not relpath(real, prefix).startswith(pardir)
for aldir in allowlist or []:
@@ -430,12 +424,12 @@ def __ext_strip_sep(ext: str) -> str:
return ext.lstrip(extsep)
-def __splitext_no_sep(path: AnyStr) -> List[str]:
+def __splitext_no_sep(path: AnyStr) -> list[str]:
path_as_str = galaxy.util.unicodify(path)
return (path_as_str.rsplit(extsep, 1) + [""])[0:2]
-def __splitext_ignore(path: AnyStr, ignore: Optional[Union[List[str], Tuple[str]]] = None) -> Tuple[str, str]:
+def __splitext_ignore(path: AnyStr, ignore: list[str] | tuple[str] | None = None) -> tuple[str, str]:
# note: unlike os.path.splitext this strips extsep from ext
ignore_map = map(__ext_strip_sep, __listify(ignore))
root, ext = __splitext_no_sep(path)
diff --git a/lib/galaxy/util/permutations.py b/lib/galaxy/util/permutations.py
index 3b316ee6c5b..c7b8454c838 100644
--- a/lib/galaxy/util/permutations.py
+++ b/lib/galaxy/util/permutations.py
@@ -10,8 +10,6 @@ with itertools product and permutations. These are open questions.
import copy
from typing import (
Any,
- Optional,
- Tuple,
)
from galaxy.exceptions import MessageException
@@ -158,7 +156,7 @@ def state_get_value(state_dict, key, nested):
return state_get_value(state_dict[first], rest, nested)
-def is_in_state(state_dict: Optional[dict], key: str, nested: bool) -> bool:
+def is_in_state(state_dict: dict | None, key: str, nested: bool) -> bool:
if not state_dict:
return False
if "|" not in key or not nested:
@@ -174,7 +172,7 @@ def looks_like_flattened_repeat_key(key: str) -> bool:
return len(parts) == 2 and parts[1].isdigit()
-def split_flattened_repeat_key(key: str) -> Tuple[str, int]:
+def split_flattened_repeat_key(key: str) -> tuple[str, int]:
input_name, _index = key.rsplit("_", 1)
index = int(_index)
return input_name, index
diff --git a/lib/galaxy/util/plugin_config.py b/lib/galaxy/util/plugin_config.py
index 83546d20a8a..14b920f2188 100644
--- a/lib/galaxy/util/plugin_config.py
+++ b/lib/galaxy/util/plugin_config.py
@@ -1,16 +1,14 @@
+from collections.abc import (
+ Generator,
+ Iterable,
+)
from types import ModuleType
from typing import (
Any,
cast,
- Dict,
- Generator,
- Iterable,
- List,
NamedTuple,
- Optional,
- Type,
+ Protocol,
TypeVar,
- Union,
)
import yaml
@@ -19,8 +17,13 @@ from galaxy.util import parse_xml
from galaxy.util.path import StrPath
from galaxy.util.submodules import import_submodules
-PluginDictConfigT = Dict[str, Any]
-PluginConfigsT = Union[PluginDictConfigT, List[PluginDictConfigT]]
+PluginDictConfigT = dict[str, Any]
+PluginConfigsT = PluginDictConfigT | list[PluginDictConfigT]
+
+
+class ConfigurablePlugin(Protocol):
+ @classmethod
+ def build_template_config(cls, **kwds: Any) -> Any: ...
class PluginConfigSource(NamedTuple):
@@ -28,7 +31,7 @@ class PluginConfigSource(NamedTuple):
source: Any
-def plugins_dict(module: ModuleType, plugin_type_identifier: str) -> Dict[str, Type]:
+def plugins_dict(module: ModuleType, plugin_type_identifier: str) -> dict[str, type]:
"""Walk through all classes in submodules of module and find ones labelled
with specified plugin_type_identifier and throw in a dictionary to allow
constructions from plugins by these types later on.
@@ -48,12 +51,12 @@ T = TypeVar("T")
def load_plugins(
- plugins_dict: Dict[str, Type[T]],
+ plugins_dict: dict[str, type[T]],
plugin_source: PluginConfigSource,
- extra_kwds: Optional[Dict[str, Any]] = None,
+ extra_kwds: dict[str, Any] | None = None,
plugin_type_keys: Iterable[str] = ("type",),
- dict_to_list_key: Optional[str] = None,
-) -> List[T]:
+ dict_to_list_key: str | None = None,
+) -> list[T]:
if extra_kwds is None:
extra_kwds = {}
if plugin_source.type == "xml":
@@ -68,7 +71,7 @@ def load_plugins(
)
-def __plugin_classes_in_module(plugin_module: ModuleType) -> Generator[Type, None, None]:
+def __plugin_classes_in_module(plugin_module: ModuleType) -> Generator[type, None, None]:
for clazz in getattr(plugin_module, "__all__", []):
try:
clazz = getattr(plugin_module, clazz)
@@ -78,8 +81,8 @@ def __plugin_classes_in_module(plugin_module: ModuleType) -> Generator[Type, Non
def __load_plugins_from_element(
- plugins_dict: Dict[str, Type[T]], plugins_element, extra_kwds: Dict[str, Any]
-) -> List[T]:
+ plugins_dict: dict[str, type[T]], plugins_element, extra_kwds: dict[str, Any]
+) -> list[T]:
plugins = []
for plugin_element in plugins_element:
@@ -98,36 +101,35 @@ def __load_plugins_from_element(
return plugins
-def __as_configurable_plugin_instance(obj: Any) -> Optional[Type]:
+def __as_configurable_plugin_instance(obj: Any) -> type[ConfigurablePlugin] | None:
"""Check if the class implements the configurable plugin pattern."""
try:
if isinstance(obj, type) and hasattr(obj, "build_template_config"):
- return obj
+ return cast(type[ConfigurablePlugin], obj)
except TypeError:
pass
return None
-def __create_plugin_instance(plugin_class: Type[T], plugin_kwds: Dict[str, Any]) -> T:
+def __create_plugin_instance(plugin_class: type[T], plugin_kwds: dict[str, Any]) -> T:
"""Create an instance of the plugin class with the provided keyword arguments."""
- configurable_instance = __as_configurable_plugin_instance(plugin_class)
- if configurable_instance:
+ if configurable_instance := __as_configurable_plugin_instance(plugin_class):
plugin_template_config = configurable_instance.build_template_config(**plugin_kwds)
- return configurable_instance(template_config=plugin_template_config)
+ return cast(T, cast(Any, configurable_instance)(template_config=plugin_template_config))
else:
return plugin_class(**plugin_kwds)
def __load_plugins_from_dicts(
- plugins_dict: Dict[str, Type[T]],
+ plugins_dict: dict[str, type[T]],
configs: PluginConfigsT,
- extra_kwds: Dict[str, Any],
+ extra_kwds: dict[str, Any],
plugin_type_keys: Iterable[str],
- dict_to_list_key: Optional[str],
-) -> List[T]:
+ dict_to_list_key: str | None,
+) -> list[T]:
plugins = []
- configs_as_list: List[PluginDictConfigT]
+ configs_as_list: list[PluginDictConfigT]
if isinstance(configs, dict) and dict_to_list_key is not None:
configs_as_list = []
for key, value in configs.items():
@@ -135,7 +137,7 @@ def __load_plugins_from_dicts(
config[dict_to_list_key] = key
configs_as_list.append(config)
else:
- configs_as_list = cast(List[PluginDictConfigT], configs)
+ configs_as_list = cast(list[PluginDictConfigT], configs)
for config in configs_as_list:
plugin_type = None
diff --git a/lib/galaxy/util/properties.py b/lib/galaxy/util/properties.py
index 296cd25f71b..678edc88318 100644
--- a/lib/galaxy/util/properties.py
+++ b/lib/galaxy/util/properties.py
@@ -6,6 +6,7 @@ this should be reusable by tool shed and pulsar as well.
import os
import os.path
import sys
+from collections.abc import Iterable
from configparser import (
BasicInterpolation,
ConfigParser,
@@ -18,8 +19,6 @@ from itertools import (
)
from typing import (
cast,
- Iterable,
- Optional,
)
import yaml
@@ -32,7 +31,7 @@ from galaxy.util.path import (
)
-def get_from_env(key: str, prefixes: Iterable[str], default: Optional[str] = None):
+def get_from_env(key: str, prefixes: Iterable[str], default: str | None = None):
"""
Return first available value for prefix+key set in the environment, or default.
An empty prefix is ignored.
diff --git a/lib/galaxy/util/requests.py b/lib/galaxy/util/requests.py
index ae809524b7a..7f42cad3506 100644
--- a/lib/galaxy/util/requests.py
+++ b/lib/galaxy/util/requests.py
@@ -1,7 +1,4 @@
-from typing import (
- Callable,
- Union,
-)
+from collections.abc import Callable
import requests
from requests import ( # noqa: F401
@@ -27,7 +24,7 @@ class Session(requests.Session):
class RetrySession(Session):
def __init__(
- self, total: Union[bool, int, None] = DEFAULT_RETRIES, backoff_factor: float = DEFAULT_BACKOFF_FACTOR, **kwargs
+ self, total: bool | int | None = DEFAULT_RETRIES, backoff_factor: float = DEFAULT_BACKOFF_FACTOR, **kwargs
) -> None:
super().__init__()
retry = Retry(total=total, backoff_factor=backoff_factor, **kwargs)
diff --git a/lib/galaxy/util/rst_to_html.py b/lib/galaxy/util/rst_to_html.py
index 1141202bb58..44962d65676 100644
--- a/lib/galaxy/util/rst_to_html.py
+++ b/lib/galaxy/util/rst_to_html.py
@@ -25,7 +25,7 @@ class FakeStream:
self.log_.warning(str)
-@functools.lru_cache(maxsize=None)
+@functools.cache
def get_publisher(error=False):
docutils_writer = docutils.writers.html4css1.Writer()
docutils_template_path = os.path.join(os.path.dirname(__file__), "docutils_template.txt")
@@ -57,7 +57,7 @@ def get_publisher(error=False):
return pub
-@functools.lru_cache(maxsize=None)
+@functools.cache
def rst_to_html(s, error=False):
if docutils is None:
raise Exception("Attempted to use rst_to_html but docutils unavailable.")
diff --git a/lib/galaxy/util/rules_dsl.py b/lib/galaxy/util/rules_dsl.py
index e3d25ecf7bb..5f3d84095e1 100644
--- a/lib/galaxy/util/rules_dsl.py
+++ b/lib/galaxy/util/rules_dsl.py
@@ -1,10 +1,6 @@
import abc
import itertools
import re
-from typing import (
- List,
- Type,
-)
import yaml
@@ -29,8 +25,7 @@ def _ensure_rule_contains_keys(rule, keys):
def _ensure_key_value_in(rule, key, values):
- value = rule[key]
- if value not in values:
+ if (value := rule[key]) not in values:
raise ValueError(f"Invalid value [{value}] for [{key}] encountered.")
@@ -654,7 +649,7 @@ class RuleSet:
return message
-RULES_DEFINITION_CLASSES: List[Type[BaseRuleDefinition]] = [
+RULES_DEFINITION_CLASSES: list[type[BaseRuleDefinition]] = [
AddColumnMetadataRuleDefinition,
AddColumnGroupTagValueRuleDefinition,
AddColumnConcatenateRuleDefinition,
diff --git a/lib/galaxy/util/search.py b/lib/galaxy/util/search.py
index d25e419038e..63760a0ec9b 100644
--- a/lib/galaxy/util/search.py
+++ b/lib/galaxy/util/search.py
@@ -1,15 +1,10 @@
import re
from typing import (
- Dict,
- List,
NamedTuple,
- Optional,
- Tuple,
- Union,
)
-KeyedQueryT = Tuple[str, str]
-ParseFilterResultT = Tuple[Optional[List["FilteredTerm"]], Optional[str]]
+KeyedQueryT = tuple[str, str]
+ParseFilterResultT = tuple[list["FilteredTerm"] | None, str | None]
QUOTE_PATTERN = re.compile(r"\'(.*?)\'")
# Defaults for `filter_terms` used by index-search callers. A whitespace-rich
@@ -19,7 +14,7 @@ DEFAULT_MIN_RAW_TERM_LENGTH = 4
DEFAULT_MAX_RAW_TERMS = 7
-def parse_filters(search_term: str, filters: Optional[Dict[str, str]] = None) -> ParseFilterResultT:
+def parse_filters(search_term: str, filters: dict[str, str] | None = None) -> ParseFilterResultT:
"""Support github-like filters for narrowing the results.
Order of chunks does not matter, only recognized filter names are allowed.
@@ -36,7 +31,7 @@ def parse_filters(search_term: str, filters: Optional[Dict[str, str]] = None) ->
def parse_filters_structured(
search_term: str,
- filters: Optional[Dict[str, str]] = None,
+ filters: dict[str, str] | None = None,
preserve_quotes: bool = True,
) -> "ParsedSearch":
search_space = search_term.replace('"', "'")
@@ -81,13 +76,13 @@ class FilteredTerm(NamedTuple):
quoted: bool
-TermT = Union[RawTextTerm, FilteredTerm]
+TermT = RawTextTerm | FilteredTerm
class ParsedSearch:
- terms: List[TermT]
- text_terms: List[RawTextTerm]
- filter_terms: List[FilteredTerm]
+ terms: list[TermT]
+ text_terms: list[RawTextTerm]
+ filter_terms: list[FilteredTerm]
def __init__(self):
self.terms = []
@@ -119,7 +114,7 @@ class ParsedSearch:
def filter_terms(
parsed: "ParsedSearch",
min_raw_term_length: int = DEFAULT_MIN_RAW_TERM_LENGTH,
- max_raw_terms: Optional[int] = DEFAULT_MAX_RAW_TERMS,
+ max_raw_terms: int | None = DEFAULT_MAX_RAW_TERMS,
) -> "ParsedSearch":
"""Return a new ParsedSearch with short / excess raw text terms dropped.
diff --git a/lib/galaxy/util/submodules.py b/lib/galaxy/util/submodules.py
index 750e0e4e227..faa57247922 100644
--- a/lib/galaxy/util/submodules.py
+++ b/lib/galaxy/util/submodules.py
@@ -2,17 +2,11 @@ import importlib
import logging
import pkgutil
from types import ModuleType
-from typing import (
- List,
- Union,
-)
log = logging.getLogger(__name__)
-def import_submodules(
- module: Union[ModuleType, str], ordered: bool = True, recursive: bool = False
-) -> List[ModuleType]:
+def import_submodules(module: ModuleType | str, ordered: bool = True, recursive: bool = False) -> list[ModuleType]:
"""Import all submodules of a module
:param module: module (package name or actual module)
@@ -35,7 +29,7 @@ def import_submodules(
return sub_modules
-def __import_submodules_impl(module: Union[ModuleType, str], recursive: bool = False) -> List[ModuleType]:
+def __import_submodules_impl(module: ModuleType | str, recursive: bool = False) -> list[ModuleType]:
"""Implementation of import only, without sorting.
:param module: module (package name or actual module)
@@ -44,7 +38,7 @@ def __import_submodules_impl(module: Union[ModuleType, str], recursive: bool = F
"""
if isinstance(module, str):
module = importlib.import_module(module)
- submodules: List[ModuleType] = []
+ submodules: list[ModuleType] = []
for _, name, is_pkg in pkgutil.walk_packages(module.__path__):
full_name = f"{module.__name__}.{name}"
try:
diff --git a/lib/galaxy/util/template.py b/lib/galaxy/util/template.py
index 2d668141f05..f5227df10d6 100644
--- a/lib/galaxy/util/template.py
+++ b/lib/galaxy/util/template.py
@@ -2,10 +2,6 @@
import sys
import traceback
-from typing import (
- Optional,
- Union,
-)
from Cheetah.Compiler import Compiler
from Cheetah.NameMapper import NotFound
@@ -112,7 +108,7 @@ def fill_template(
compiler_class=Compiler,
first_exception=None,
futurized=False,
- python_template_version: Optional[Union[str, Version]] = "3",
+ python_template_version: str | Version | None = "3",
**kwargs,
):
"""Fill a cheetah template out for specified context.
diff --git a/lib/galaxy/util/themes.py b/lib/galaxy/util/themes.py
index ba9901d62d3..249a3f05432 100644
--- a/lib/galaxy/util/themes.py
+++ b/lib/galaxy/util/themes.py
@@ -1,20 +1,19 @@
from typing import (
- Dict,
Union,
)
-Theme = Dict[str, Union["Theme", str]]
+Theme = dict[str, Union["Theme", str]]
-def flatten_theme(theme: Theme, prefix: str = "-") -> Dict[str, str]:
+def flatten_theme(theme: Theme, prefix: str = "-") -> dict[str, str]:
"""Transforms a nested theme dictionary into a flat dictionary,
containing keys compatible with css variables. e.g. '--masthead-background-color'"""
- flat_attributes: Dict[str, str] = {}
+ flat_attributes: dict[str, str] = {}
for key, val in theme.items():
if isinstance(val, str):
flat_attributes[f"{prefix}-{key}"] = val
- elif isinstance(val, Dict):
+ elif isinstance(val, dict):
flat_attributes.update(flatten_theme(val, f"{prefix}-{key}"))
return flat_attributes
diff --git a/lib/galaxy/util/tool_shed/common_util.py b/lib/galaxy/util/tool_shed/common_util.py
index c5ff49da155..fddc8e0dffa 100644
--- a/lib/galaxy/util/tool_shed/common_util.py
+++ b/lib/galaxy/util/tool_shed/common_util.py
@@ -2,7 +2,6 @@ import json
import logging
import os
from typing import (
- Optional,
TYPE_CHECKING,
)
from urllib.parse import urljoin
@@ -35,8 +34,7 @@ def accumulate_tool_dependencies(tool_shed_accessible, tool_dependencies, all_to
def check_tool_tag_set(elem, migrated_tool_configs_dict, missing_tool_configs_dict):
- file_path = elem.get("file", None)
- if file_path:
+ if file_path := elem.get("file", None):
name = os.path.basename(file_path)
for migrated_tool_config in migrated_tool_configs_dict.keys():
if migrated_tool_config in [file_path, name]:
@@ -126,7 +124,7 @@ def get_tool_shed_repository_ids(as_string=False, **kwd):
return []
-def get_tool_shed_url_from_tool_shed_registry(app: HasToolShedRegistry, tool_shed: str) -> Optional[str]:
+def get_tool_shed_url_from_tool_shed_registry(app: HasToolShedRegistry, tool_shed: str) -> str | None:
"""
The value of tool_shed is something like: toolshed.g2.bx.psu.edu. We need the URL to this tool shed, which is
something like: http://toolshed.g2.bx.psu.edu/
diff --git a/lib/galaxy/util/tool_shed/tool_shed_registry.py b/lib/galaxy/util/tool_shed/tool_shed_registry.py
index c1a60aa56dc..dab1fd7ef28 100644
--- a/lib/galaxy/util/tool_shed/tool_shed_registry.py
+++ b/lib/galaxy/util/tool_shed/tool_shed_registry.py
@@ -1,12 +1,9 @@
import logging
from typing import (
- Dict,
+ Literal,
NamedTuple,
- Optional,
)
-from typing_extensions import Literal
-
from galaxy.util import parse_xml_string
from galaxy.util.path import StrPath
from galaxy.util.tool_shed import common_util
@@ -31,11 +28,11 @@ class AUTH_TUPLE(NamedTuple):
class Registry:
- tool_sheds: Dict[str, str]
- tool_shed_api_versions: Dict[str, API_VERSION]
- tool_sheds_auth: Dict[str, Optional[AUTH_TUPLE]]
+ tool_sheds: dict[str, str]
+ tool_shed_api_versions: dict[str, API_VERSION]
+ tool_sheds_auth: dict[str, AUTH_TUPLE | None]
- def __init__(self, config: Optional[StrPath] = None):
+ def __init__(self, config: StrPath | None = None):
self.tool_sheds = {}
self.tool_sheds_auth = {}
self.tool_shed_api_versions = {}
@@ -72,7 +69,7 @@ class Registry:
except Exception as e:
log.warning(f'Error loading reference to tool shed "{name}", problem: {str(e)}')
- def url_auth(self, url: str) -> Optional[AUTH_TUPLE]:
+ def url_auth(self, url: str) -> AUTH_TUPLE | None:
"""
If the tool shed is using external auth, the client to the tool shed must authenticate to that
as well. This provides access to the six.moves.urllib.request.HTTPPasswordMgrWithdefaultRealm() object for the
@@ -81,8 +78,7 @@ class Registry:
Following more what galaxy.demo_sequencer.controllers.common does might be more appropriate at
some stage...
"""
- shed_name = self._shed_name_for_url(url)
- if shed_name is not None:
+ if (shed_name := self._shed_name_for_url(url)) is not None:
return self.tool_sheds_auth[shed_name]
else:
log.debug(f"Invalid url '{str(url)}' received by tool shed registry's url_auth method.")
@@ -95,7 +91,7 @@ class Registry:
else:
return self.tool_shed_api_versions[shed_name] == "v1"
- def _shed_name_for_url(self, url: str) -> Optional[str]:
+ def _shed_name_for_url(self, url: str) -> str | None:
url_sans_protocol = common_util.remove_protocol_from_tool_shed_url(url)
for shed_name, shed_url in self.tool_sheds.items():
shed_url_sans_protocol = common_util.remove_protocol_from_tool_shed_url(shed_url)
@@ -103,7 +99,7 @@ class Registry:
return shed_name
return None
- def get_tool_shed_url(self, tool_shed: str) -> Optional[str]:
+ def get_tool_shed_url(self, tool_shed: str) -> str | None:
"""
The value of tool_shed is something like: toolshed.g2.bx.psu.edu. We need the URL to this tool shed, which is
something like: http://toolshed.g2.bx.psu.edu/
diff --git a/lib/galaxy/util/tool_shed/xml_util.py b/lib/galaxy/util/tool_shed/xml_util.py
index 0aee018cd5e..5e1dde79cbd 100644
--- a/lib/galaxy/util/tool_shed/xml_util.py
+++ b/lib/galaxy/util/tool_shed/xml_util.py
@@ -1,10 +1,6 @@
import logging
import os
import tempfile
-from typing import (
- Optional,
- Tuple,
-)
from galaxy.util import (
Element,
@@ -26,7 +22,7 @@ def create_and_write_tmp_file(elem: Element) -> str:
return tmp_filename
-def parse_xml(file_name: StrPath, check_exists=True) -> Tuple[Optional[ElementTree], str]:
+def parse_xml(file_name: StrPath, check_exists=True) -> tuple[ElementTree | None, str]:
"""Returns a parsed xml tree with comments intact."""
error_message = ""
if check_exists and not os.path.exists(file_name):
diff --git a/lib/galaxy/util/tool_version.py b/lib/galaxy/util/tool_version.py
index b647eb69419..79ce88fda82 100644
--- a/lib/galaxy/util/tool_version.py
+++ b/lib/galaxy/util/tool_version.py
@@ -1,7 +1,4 @@
-from typing import Union
-
-
-def remove_version_from_guid(guid: str) -> Union[str, None]:
+def remove_version_from_guid(guid: str) -> str | None:
"""
Removes version from toolshed-derived tool_id(=guid).
"""
diff --git a/lib/galaxy/util/tree_dict.py b/lib/galaxy/util/tree_dict.py
index b5c58a34b67..7c384754e5d 100644
--- a/lib/galaxy/util/tree_dict.py
+++ b/lib/galaxy/util/tree_dict.py
@@ -5,7 +5,6 @@ from collections.abc import (
)
from typing import (
Any,
- Optional,
)
from boltons.iterutils import remap
@@ -24,7 +23,7 @@ class TreeDict(UserDict):
"""
def __init__(self, dict=None, **kwargs):
- self._parent_data: Optional[TreeDict] = None
+ self._parent_data: TreeDict | None = None
self._injected_data = {}
super().__init__(dict, **kwargs)
diff --git a/lib/galaxy/util/unittest_utils/__init__.py b/lib/galaxy/util/unittest_utils/__init__.py
index 1b67932b4f9..5a88b64864b 100644
--- a/lib/galaxy/util/unittest_utils/__init__.py
+++ b/lib/galaxy/util/unittest_utils/__init__.py
@@ -1,10 +1,9 @@
import os
+from collections.abc import Callable
from datetime import datetime
from functools import wraps
from typing import (
- Callable,
TypeVar,
- Union,
)
from unittest import SkipTest
@@ -48,13 +47,13 @@ def _identity(func: Callable[P, T]) -> Callable[P, T]:
return func
-def skip_unless_executable(executable: str) -> Union[Callable[[Callable[P, T]], Callable[P, T]], pytest.MarkDecorator]:
+def skip_unless_executable(executable: str) -> Callable[[Callable[P, T]], Callable[P, T]] | pytest.MarkDecorator:
if which(executable):
return _identity
return pytest.mark.skip(f"PATH doesn't contain executable {executable}")
-def skip_unless_environ(env_var: str) -> Union[Callable[[Callable[P, T]], Callable[P, T]], pytest.MarkDecorator]:
+def skip_unless_environ(env_var: str) -> Callable[[Callable[P, T]], Callable[P, T]] | pytest.MarkDecorator:
if os.environ.get(env_var):
return _identity
diff --git a/lib/galaxy/util/wait.py b/lib/galaxy/util/wait.py
index 4fbe6ad3373..6774e435888 100644
--- a/lib/galaxy/util/wait.py
+++ b/lib/galaxy/util/wait.py
@@ -1,17 +1,13 @@
"""Abstraction for waiting on API conditions to become true."""
import time
-from typing import (
- Callable,
- Optional,
- Union,
-)
+from collections.abc import Callable
DEFAULT_POLLING_BACKOFF = 0
DEFAULT_POLLING_DELTA = 0.25
TIMEOUT_MESSAGE_TEMPLATE = "Timed out after {} seconds waiting on {}."
-timeout_type = Union[int, float]
+timeout_type = int | float
def wait_on(
@@ -20,7 +16,7 @@ def wait_on(
timeout: timeout_type,
delta: timeout_type = DEFAULT_POLLING_DELTA,
polling_backoff: timeout_type = DEFAULT_POLLING_BACKOFF,
- sleep_: Optional[Callable] = None,
+ sleep_: Callable | None = None,
):
"""Wait for function to return non-None value.
diff --git a/lib/galaxy/util/watcher.py b/lib/galaxy/util/watcher.py
index 141fd8136e0..b50568153a2 100644
--- a/lib/galaxy/util/watcher.py
+++ b/lib/galaxy/util/watcher.py
@@ -144,8 +144,7 @@ class EventHandler(FileSystemEventHandler):
self._handle(event)
def _extension_check(self, key, path):
- required_extensions = self.watcher.require_extensions.get(key)
- if required_extensions:
+ if required_extensions := self.watcher.require_extensions.get(key):
return any(filter(path.endswith, required_extensions))
return not any(filter(path.endswith, self.watcher.ignore_extensions.get(key, [])))
@@ -169,8 +168,7 @@ class EventHandler(FileSystemEventHandler):
break
if not callback or not ext_ok:
return
- cur_hash = md5_hash_file(path)
- if cur_hash:
+ if cur_hash := md5_hash_file(path):
if self.watcher.path_hash.get(path) == cur_hash:
return
else:
diff --git a/lib/galaxy/util/xml_macros.py b/lib/galaxy/util/xml_macros.py
index 09c8a950330..eff4ac0a4c2 100644
--- a/lib/galaxy/util/xml_macros.py
+++ b/lib/galaxy/util/xml_macros.py
@@ -1,12 +1,10 @@
import os
+from collections.abc import (
+ Callable,
+ Iterable,
+)
from copy import deepcopy
from typing import (
- Callable,
- Dict,
- Iterable,
- List,
- Optional,
- Tuple,
TYPE_CHECKING,
TypeVar,
Union,
@@ -24,10 +22,10 @@ if TYPE_CHECKING:
)
from galaxy.util.path import StrPath
-MacrosDictT = Dict[str, List["Element"]]
+MacrosDictT = dict[str, list["Element"]]
-def load_with_references(path: "StrPath") -> Tuple["ElementTree", Optional[List[str]]]:
+def load_with_references(path: "StrPath") -> tuple["ElementTree", list[str] | None]:
"""Load XML documentation from file system and preprocesses XML macros.
Return the XML representation of the expanded tree and paths to
@@ -45,7 +43,7 @@ def load_with_references(path: "StrPath") -> Tuple["ElementTree", Optional[List[
macros_el.clear()
# Collect tokens
- tokens: Dict[str, str] = {}
+ tokens: dict[str, str] = {}
for m in macros.get("token", []):
token_name = m.get("name")
assert token_name
@@ -53,7 +51,7 @@ def load_with_references(path: "StrPath") -> Tuple["ElementTree", Optional[List[
tokens = expand_nested_tokens(tokens)
# Expand xml macros
- macro_dict: Dict[str, XmlMacroDef] = {}
+ macro_dict: dict[str, XmlMacroDef] = {}
for m in macros.get("xml", []):
macro_name = m.get("name")
assert macro_name
@@ -72,13 +70,12 @@ def load(path: "StrPath") -> "ElementTree":
return tree
-def template_macro_params(root: "Element") -> Dict[str, Union[str, None]]:
+def template_macro_params(root: "Element") -> dict[str, str | None]:
"""
Look for template macros and populate param_dict (for cheetah)
with these.
"""
- macros_el = _macros_el(root)
- if macros_el is not None:
+ if (macros_el := _macros_el(root)) is not None:
return _macros_of_type(macros_el, "template", lambda el: el.text)
return {}
@@ -91,14 +88,14 @@ def raw_xml_tree(path: "StrPath") -> "ElementTree":
return tree
-def imported_macro_paths(root: "Element") -> List[str]:
+def imported_macro_paths(root: "Element") -> list[str]:
macros_el = _macros_el(root)
if macros_el is None:
return []
return _imported_macro_paths_from_el(macros_el)
-def _import_macros(macros_el: "Element", path: "StrPath", macros: MacrosDictT) -> Optional[List[str]]:
+def _import_macros(macros_el: "Element", path: "StrPath", macros: MacrosDictT) -> list[str] | None:
"""
root the parsed XML tree
path the path to the main xml document
@@ -116,9 +113,9 @@ def _macros_el(root: "Element") -> Union["Element", None]:
T = TypeVar("T")
-def _macros_of_type(macros_el: "Element", type: str, el_func: Callable[["Element"], T]) -> Dict[str, T]:
+def _macros_of_type(macros_el: "Element", type: str, el_func: Callable[["Element"], T]) -> dict[str, T]:
macro_els = macros_el.findall("macro")
- ret: Dict[str, T] = {}
+ ret: dict[str, T] = {}
for macro_el in macro_els:
if macro_el.get("type") == type:
macro_name = macro_el.get("name")
@@ -127,7 +124,7 @@ def _macros_of_type(macros_el: "Element", type: str, el_func: Callable[["Element
return ret
-def expand_nested_tokens(tokens: Dict[str, str]) -> Dict[str, str]:
+def expand_nested_tokens(tokens: dict[str, str]) -> dict[str, str]:
for token_name in tokens.keys():
for current_token_name, current_token_value in tokens.items():
if token_name in current_token_value:
@@ -137,7 +134,7 @@ def expand_nested_tokens(tokens: Dict[str, str]) -> Dict[str, str]:
return tokens
-def _expand_tokens(elements: Iterable["Element"], tokens: Dict[str, str]) -> None:
+def _expand_tokens(elements: Iterable["Element"], tokens: dict[str, str]) -> None:
if not tokens:
return
@@ -145,14 +142,13 @@ def _expand_tokens(elements: Iterable["Element"], tokens: Dict[str, str]) -> Non
_expand_tokens_for_el(element, tokens)
-def _expand_tokens_for_el(element: "Element", tokens: Dict[str, str]) -> None:
+def _expand_tokens_for_el(element: "Element", tokens: dict[str, str]) -> None:
"""
expand tokens in element and (recursively) in its children
replacements of text attributes and attribute values are
possible
"""
- element_text = element.text
- if element_text:
+ if element_text := element.text:
new_value = _expand_tokens_str(element_text, tokens)
if new_value is not element_text:
element.text = new_value
@@ -168,7 +164,7 @@ def _expand_tokens_for_el(element: "Element", tokens: Dict[str, str]) -> None:
_expand_tokens(element.__iter__(), tokens)
-def _expand_tokens_str(s: str, tokens: Dict[str, str]) -> str:
+def _expand_tokens_str(s: str, tokens: dict[str, str]) -> str:
for key, value in tokens.items():
if key in s:
s = s.replace(key, value)
@@ -177,9 +173,9 @@ def _expand_tokens_str(s: str, tokens: Dict[str, str]) -> str:
def _expand_macros(
elements: Iterable["Element"],
- macros: Dict[str, "XmlMacroDef"],
- tokens: Dict[str, str],
- visited: Optional[List[str]] = None,
+ macros: dict[str, "XmlMacroDef"],
+ tokens: dict[str, str],
+ visited: list[str] | None = None,
) -> None:
if not macros and not tokens:
return
@@ -196,7 +192,7 @@ def _expand_macros(
def _expand_macro(
- expand_el: "Element", macros: Dict[str, "XmlMacroDef"], tokens: Dict[str, str], visited: List[str]
+ expand_el: "Element", macros: dict[str, "XmlMacroDef"], tokens: dict[str, str], visited: list[str]
) -> None:
macro_name = expand_el.get("macro")
assert macro_name is not None, "Attempted to expand macro with no 'macro' attribute defined."
@@ -211,8 +207,7 @@ def _expand_macro(
macro_el = deepcopy(macro_def.element)
_expand_yield_statements(macro_el, expand_el)
- macro_tokens = macro_def.macro_tokens(expand_el)
- if macro_tokens:
+ if macro_tokens := macro_def.macro_tokens(expand_el):
_expand_tokens(macro_el.__iter__(), macro_tokens)
# Recursively expand contained macros.
@@ -245,7 +240,7 @@ def _expand_yield_statements(macro_el: "Element", expand_el: "Element") -> None:
_xml_replace(yield_el, expand_el_children)
-def _load_macros(macros_el: "Element", xml_base_dir: str, macros: MacrosDictT) -> List[str]:
+def _load_macros(macros_el: "Element", xml_base_dir: str, macros: MacrosDictT) -> list[str]:
# Import macros from external files.
macro_paths = _load_imported_macros(macros_el, xml_base_dir, macros)
# Load all directly defined macros.
@@ -276,7 +271,7 @@ def _load_embedded_macros(macros_el: "Element", macros: MacrosDictT) -> None:
macros[tag] = [macro_el]
-def _load_imported_macros(macros_el: "Element", xml_base_dir: str, macros: MacrosDictT) -> List[str]:
+def _load_imported_macros(macros_el: "Element", xml_base_dir: str, macros: MacrosDictT) -> list[str]:
macro_paths = []
for tool_relative_import_path in _imported_macro_paths_from_el(macros_el):
@@ -287,7 +282,7 @@ def _load_imported_macros(macros_el: "Element", xml_base_dir: str, macros: Macro
return macro_paths
-def _imported_macro_paths_from_el(macros_el: "Element") -> List[str]:
+def _imported_macro_paths_from_el(macros_el: "Element") -> list[str]:
imported_macro_paths = []
for macro_import_el in macros_el.findall("import"):
raw_import_path = macro_import_el.text
@@ -296,7 +291,7 @@ def _imported_macro_paths_from_el(macros_el: "Element") -> List[str]:
return imported_macro_paths
-def _load_macro_file(path: "StrPath", xml_base_dir: str, macros: MacrosDictT) -> List[str]:
+def _load_macro_file(path: "StrPath", xml_base_dir: str, macros: MacrosDictT) -> list[str]:
tree = parse_xml(path, strip_whitespace=False)
root = tree.getroot()
return _load_macros(root, xml_base_dir, macros)
@@ -340,7 +335,7 @@ class XmlMacroDef:
def __init__(self, el: "Element") -> None:
self.element = el
- tokens: Dict[str, Union[str, None]] = {}
+ tokens: dict[str, str | None] = {}
self.token_quote = "@"
for key, value in el.attrib.items():
key = unicodify(key)
@@ -355,14 +350,14 @@ class XmlMacroDef:
tokens[token] = value
self.tokens = tokens
- def macro_tokens(self, expand_el: "Element") -> Dict[str, str]:
+ def macro_tokens(self, expand_el: "Element") -> dict[str, str]:
"""
get a dictionary mapping token names to values. The names are the
parameter names surrounded by the quote character. Values are taken
from the expand_el if absent default values of optional parameters are
used.
"""
- tokens: Dict[str, str] = {}
+ tokens: dict[str, str] = {}
for key, default_val in self.tokens.items():
token_value = expand_el.attrib.get(key, default_val)
if token_value is None:
diff --git a/lib/galaxy/util/zipstream.py b/lib/galaxy/util/zipstream.py
index 7b81d1c33f4..2be203000b2 100644
--- a/lib/galaxy/util/zipstream.py
+++ b/lib/galaxy/util/zipstream.py
@@ -1,12 +1,6 @@
import os
import zlib
-from typing import (
- Dict,
- Iterator,
- List,
- Optional,
- Set,
-)
+from collections.abc import Iterator
from urllib.parse import quote
import zipstream
@@ -20,7 +14,7 @@ CRC32_MAX = 1459
class ZipstreamWrapper:
def __init__(
- self, archive_name: Optional[str] = None, upstream_mod_zip: bool = False, upstream_gzip: bool = False
+ self, archive_name: str | None = None, upstream_mod_zip: bool = False, upstream_gzip: bool = False
) -> None:
self.upstream_mod_zip = upstream_mod_zip
self.archive_name = archive_name
@@ -28,8 +22,8 @@ class ZipstreamWrapper:
self.archive = zipstream.ZipFile(
allowZip64=True, compression=zipstream.ZIP_STORED if upstream_gzip else zipstream.ZIP_DEFLATED
)
- self.files: List[str] = []
- self.directories: Set[str] = set()
+ self.files: list[str] = []
+ self.directories: set[str] = set()
self.size = 0
def response(self) -> Iterator[bytes]:
@@ -39,7 +33,7 @@ class ZipstreamWrapper:
else:
yield from iter(self.archive)
- def get_headers(self) -> Dict[str, str]:
+ def get_headers(self) -> dict[str, str]:
headers = {}
if self.archive_name:
headers["Content-Disposition"] = to_content_disposition(f"{self.archive_name}.zip")
@@ -69,7 +63,7 @@ class ZipstreamWrapper:
self.size += size
self.archive.write(path, archive_name)
- def write(self, path: str, archive_name: Optional[str] = None) -> None:
+ def write(self, path: str, archive_name: str | None = None) -> None:
if os.path.isdir(path):
pardir = os.path.join(path, os.pardir)
for root, directories, files in safe_walk(path):
diff --git a/lib/galaxy/visualization/data_providers/genome.py b/lib/galaxy/visualization/data_providers/genome.py
index 2c9e7b7d4ce..17a3021daa0 100644
--- a/lib/galaxy/visualization/data_providers/genome.py
+++ b/lib/galaxy/visualization/data_providers/genome.py
@@ -16,8 +16,6 @@ from json import loads
from typing import (
Any,
IO,
- Optional,
- Union,
)
import pysam
@@ -44,7 +42,7 @@ from galaxy.visualization.data_providers.cigar import get_ref_based_read_seq_and
log = logging.getLogger(__name__)
-IntWebParam = Union[str, int]
+IntWebParam = str | int
#
# Utility functions.
@@ -54,7 +52,7 @@ IntWebParam = Union[str, int]
# Can be removed once https://github.com/pysam-developers/pysam/issues/939 is resolved.
pysam.set_verbosity(0)
-PAYLOAD_LIST_TYPE = list[Optional[Union[str, int, float, list[tuple[int, int]]]]]
+PAYLOAD_LIST_TYPE = list[str | int | float | list[tuple[int, int]] | None]
def float_nan(n):
@@ -174,7 +172,7 @@ class GenomeDataProvider(BaseDataProvider):
# filters. Key is column name, value is a dict with mandatory key 'index'
# and optional key 'name'. E.g. this defines column 4:
# col_name_data_attr_mapping = {4 : { index: 5, name: 'Score' } }
- col_name_data_attr_mapping: dict[Union[str, int], dict] = {}
+ col_name_data_attr_mapping: dict[str | int, dict] = {}
def __init__(
self,
@@ -358,7 +356,7 @@ class TabixDataProvider(GenomeDataProvider, FilterableMixin):
dataset_type = "tabix"
- col_name_data_attr_mapping: dict[Union[str, int], dict] = {4: {"index": 4, "name": "Score"}}
+ col_name_data_attr_mapping: dict[str | int, dict] = {4: {"index": 4, "name": "Score"}}
@contextmanager
def open_data_file(self):
@@ -622,7 +620,7 @@ class VcfDataProvider(GenomeDataProvider):
"""
- col_name_data_attr_mapping: dict[Union[str, int], dict] = {"Qual": {"index": 6, "name": "Qual"}}
+ col_name_data_attr_mapping: dict[str | int, dict] = {"Qual": {"index": 6, "name": "Qual"}}
dataset_type = "variant"
@@ -762,7 +760,7 @@ class RawVcfDataProvider(VcfDataProvider):
def get_iterator(self, data_file, chrom, start, end, **kwargs) -> Iterator[str]:
# Skip comments.
- line: Optional[str] = None
+ line: str | None = None
for line in data_file:
if not line.startswith("#"):
break
@@ -1107,7 +1105,7 @@ class BBIDataProvider(GenomeDataProvider):
dataset_type = "bigwig"
@abc.abstractmethod
- def _get_dataset(self) -> tuple[IO[bytes], Union[BigBedFile, BigWigFile]]: ...
+ def _get_dataset(self) -> tuple[IO[bytes], BigBedFile | BigWigFile]: ...
def valid_chroms(self):
# No way to return this info as of now
diff --git a/lib/galaxy/visualization/data_providers/phyloviz/nexusparser.py b/lib/galaxy/visualization/data_providers/phyloviz/nexusparser.py
index 89fd65ce521..9660e1ee475 100644
--- a/lib/galaxy/visualization/data_providers/phyloviz/nexusparser.py
+++ b/lib/galaxy/visualization/data_providers/phyloviz/nexusparser.py
@@ -58,8 +58,9 @@ class Nexus_Parser(Newick_Parser):
if intranslateBlock:
mappingLine = self.splitLinebyWhitespaces(line)
- key, value = mappingLine[1], mappingLine[2].replace(",", "").replace(
- "'", ""
+ key, value = (
+ mappingLine[1],
+ mappingLine[2].replace(",", "").replace("'", ""),
) # replacing illegal json characters
self.nameMapping[key] = value
diff --git a/lib/galaxy/visualization/data_providers/registry.py b/lib/galaxy/visualization/data_providers/registry.py
index b5330691c8e..5d65847c973 100644
--- a/lib/galaxy/visualization/data_providers/registry.py
+++ b/lib/galaxy/visualization/data_providers/registry.py
@@ -1,7 +1,5 @@
from typing import (
Literal,
- Optional,
- Union,
)
from galaxy.datatypes.data import (
@@ -32,8 +30,8 @@ from galaxy.visualization.data_providers.basic import (
from galaxy.visualization.data_providers.phyloviz import PhylovizDataProvider
# a dict keyed on datatype with a 'default' string key.
-PROVIDER_BY_DATATYPE_CLASS_DICT = dict[Union[Literal["default"], type[Data]], type[BaseDataProvider]]
-DATA_PROVIDER_BY_TYPE_NAME_DICT = dict[str, Union[type[BaseDataProvider], PROVIDER_BY_DATATYPE_CLASS_DICT]]
+PROVIDER_BY_DATATYPE_CLASS_DICT = dict[Literal["default"] | type[Data], type[BaseDataProvider]]
+DATA_PROVIDER_BY_TYPE_NAME_DICT = dict[str, type[BaseDataProvider] | PROVIDER_BY_DATATYPE_CLASS_DICT]
class DataProviderRegistry:
@@ -69,7 +67,7 @@ class DataProviderRegistry:
sources, source parameter is ignored.
"""
- data_provider: Optional[BaseDataProvider]
+ data_provider: BaseDataProvider | None
data_provider_class: type[BaseDataProvider]
# any datatype class that is a subclass of another needs to be
diff --git a/lib/galaxy/visualization/genomes.py b/lib/galaxy/visualization/genomes.py
index 2c7195a0523..fe7f9c210a1 100644
--- a/lib/galaxy/visualization/genomes.py
+++ b/lib/galaxy/visualization/genomes.py
@@ -3,9 +3,6 @@ import os
import re
import sys
from json import loads
-from typing import (
- Optional,
-)
from bx.seq.twobit import TwoBitFile
@@ -261,7 +258,7 @@ class Genomes:
rval = self.genomes[dbkey]
return rval
- def get_dbkeys(self, user: Optional[User], chrom_info=False):
+ def get_dbkeys(self, user: User | None, chrom_info=False):
"""Returns all known dbkeys. If chrom_info is True, only dbkeys with
chromosome lengths are returned."""
self.check_and_reload()
diff --git a/lib/galaxy/visualization/plugins/datasource_testing.py b/lib/galaxy/visualization/plugins/datasource_testing.py
index 59f5bd2423c..cb922b4cc30 100644
--- a/lib/galaxy/visualization/plugins/datasource_testing.py
+++ b/lib/galaxy/visualization/plugins/datasource_testing.py
@@ -1,7 +1,4 @@
import logging
-from typing import (
- Optional,
-)
log = logging.getLogger(__name__)
@@ -24,7 +21,7 @@ def _check_uri_support(target_object, supported_protocols: list[str]) -> bool:
return False
-def _deferred_source_uri(target_object) -> Optional[str]:
+def _deferred_source_uri(target_object) -> str | None:
"""Get the source uri from a deferred object."""
sources = getattr(target_object, "sources", None)
if sources and sources[0]:
diff --git a/lib/galaxy/visualization/plugins/registry.py b/lib/galaxy/visualization/plugins/registry.py
index 9a192ac1523..43532d09d57 100644
--- a/lib/galaxy/visualization/plugins/registry.py
+++ b/lib/galaxy/visualization/plugins/registry.py
@@ -10,7 +10,6 @@ import os
import weakref
from typing import (
TYPE_CHECKING,
- Union,
)
import galaxy.model
@@ -46,7 +45,7 @@ class VisualizationsRegistry:
return self.__class__.__name__
def __init__(
- self, app: "StructuredApp", directories_setting: Union[str, None] = None, skip_bad_plugins: bool = True
+ self, app: "StructuredApp", directories_setting: str | None = None, skip_bad_plugins: bool = True
) -> None:
"""
Set up the manager and load all visualization plugins.
diff --git a/lib/galaxy/visualization/plugins/resource_parser.py b/lib/galaxy/visualization/plugins/resource_parser.py
index af24e3c8e01..9c58075e8d2 100644
--- a/lib/galaxy/visualization/plugins/resource_parser.py
+++ b/lib/galaxy/visualization/plugins/resource_parser.py
@@ -7,10 +7,6 @@ import json
import logging
import weakref
from collections.abc import Callable
-from typing import (
- Optional,
- Union,
-)
import galaxy.exceptions
import galaxy.util
@@ -28,10 +24,8 @@ from galaxy.util import bunch
log = logging.getLogger(__name__)
-ParameterPrimitiveType = Union[int, float, str]
-ParameterType = Union[
- ParameterPrimitiveType, HistoryDatasetAssociation, LibraryDatasetDatasetAssociation, Visualization
-]
+ParameterPrimitiveType = int | float | str
+ParameterType = ParameterPrimitiveType | HistoryDatasetAssociation | LibraryDatasetDatasetAssociation | Visualization
class ResourceParser:
@@ -156,20 +150,20 @@ class ResourceParser:
# TODO: I would LOVE to rip modifiers out completely
def parse_parameter_modifiers(
self, trans, param_modifiers, query_params
- ) -> dict[str, dict[str, Optional[ParameterType]]]:
+ ) -> dict[str, dict[str, ParameterType | None]]:
"""
Parse and return parameters that are meant to modify other parameters,
be grouped with them, or are needed to successfully parse other parameters.
"""
# only one level of modification - down that road lies madness
# parse the modifiers out of query_params first since they modify the other params coming next
- parsed_modifiers: dict[str, dict[str, Optional[ParameterType]]] = {}
+ parsed_modifiers: dict[str, dict[str, ParameterType | None]] = {}
if not param_modifiers:
return parsed_modifiers
# precondition: expects a two level dictionary
# { target_param_name -> { param_modifier_name -> { param_modifier_data }}}
for target_param_name, modifier_dict in param_modifiers.items():
- target_modifiers: dict[str, Optional[ParameterType]] = {}
+ target_modifiers: dict[str, ParameterType | None] = {}
parsed_modifiers[target_param_name] = target_modifiers
for modifier_name, modifier_config in modifier_dict.items():
@@ -183,7 +177,7 @@ class ResourceParser:
return parsed_modifiers
- def parse_parameter_default(self, trans, param_config) -> Optional[ParameterType]:
+ def parse_parameter_default(self, trans, param_config) -> ParameterType | None:
"""
Parse any default values for the given param, defaulting the default
to `None`.
@@ -204,7 +198,7 @@ class ResourceParser:
a resource usable directly by a template.
"""
param_type = expected_param_data.get("type")
- parsed_param: Optional[ParameterType] = None
+ parsed_param: ParameterType | None = None
if param_type in self.primitive_parsers:
# TODO: what about param modifiers on primitives?
diff --git a/lib/galaxy/web/framework/helpers/grids.py b/lib/galaxy/web/framework/helpers/grids.py
index bc9364751dd..eb1c6e07bd2 100644
--- a/lib/galaxy/web/framework/helpers/grids.py
+++ b/lib/galaxy/web/framework/helpers/grids.py
@@ -1,7 +1,4 @@
import logging
-from typing import (
- Optional,
-)
from markupsafe import escape
@@ -64,7 +61,7 @@ class GridData:
Specifies the content a grid (data table).
"""
- model_class: Optional[type] = None
+ model_class: type | None = None
columns: list[GridColumn] = []
default_limit: int = 1000
diff --git a/lib/galaxy/web/framework/middleware/aiocop_integration.py b/lib/galaxy/web/framework/middleware/aiocop_integration.py
index 6892683ec49..5ca250f49de 100644
--- a/lib/galaxy/web/framework/middleware/aiocop_integration.py
+++ b/lib/galaxy/web/framework/middleware/aiocop_integration.py
@@ -21,7 +21,6 @@ import threading
from contextvars import ContextVar
from typing import (
Any,
- Optional,
)
from starlette.types import (
@@ -40,7 +39,7 @@ ENV_VAR = "GALAXY_TEST_AIOCOP"
# Anything at or above is considered a test-failing violation.
HIGH_SEVERITY_SCORE = 50
-_request_violations: ContextVar[Optional[list[dict[str, Any]]]] = ContextVar("aiocop_request_violations", default=None)
+_request_violations: ContextVar[list[dict[str, Any]] | None] = ContextVar("aiocop_request_violations", default=None)
_process_initialized = False
@@ -52,8 +51,7 @@ def aiocop_enabled() -> bool:
def _on_slow_task(event: Any) -> None:
if not event.blocking_events:
return
- violations = _request_violations.get()
- if violations is not None:
+ if (violations := _request_violations.get()) is not None:
violations.extend(event.blocking_events)
log.error(
"aiocop detected blocking I/O on event loop (severity=%s, elapsed=%.1fms): %s",
@@ -162,8 +160,7 @@ class AiocopMiddleware:
max_severity = max(int(v.get("severity") or 0) for v in violations)
first = violations[0]
summary = (
- f"count={len(violations)};severity={max_severity};"
- f"first={first['event']}@{first['entry_point']}"
+ f"count={len(violations)};severity={max_severity};first={first['event']}@{first['entry_point']}"
)
headers = list(message.get("headers", []))
headers.append((b"x-aiocop-violations", summary.encode("latin-1")))
diff --git a/lib/galaxy/web/statsd_client.py b/lib/galaxy/web/statsd_client.py
index 02a230ce76d..6e4ac756323 100644
--- a/lib/galaxy/web/statsd_client.py
+++ b/lib/galaxy/web/statsd_client.py
@@ -1,7 +1,4 @@
import sys
-from typing import (
- Optional,
-)
try:
import statsd
@@ -51,8 +48,8 @@ class VanillaGalaxyStatsdClient:
return ""
-CURRENT_TEST: Optional[str] = None
-CURRENT_TEST_METRICS: Optional[dict[str, dict]] = None
+CURRENT_TEST: str | None = None
+CURRENT_TEST_METRICS: dict[str, dict] | None = None
class PyTestGalaxyStatsdClient(VanillaGalaxyStatsdClient):
diff --git a/lib/galaxy/web_stack/__init__.py b/lib/galaxy/web_stack/__init__.py
index 44accd7ba68..83925f54f9e 100644
--- a/lib/galaxy/web_stack/__init__.py
+++ b/lib/galaxy/web_stack/__init__.py
@@ -7,7 +7,6 @@ import sys
import threading
from collections.abc import Callable
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -27,7 +26,7 @@ class ApplicationStackLogFilter(logging.Filter):
class ApplicationStack:
- name: Optional[str] = None
+ name: str | None = None
prohibited_middleware: frozenset[str] = frozenset()
log_filter_class: type[logging.Filter] = ApplicationStackLogFilter
log_format = "%(name)s %(levelname)s %(asctime)s [pN:%(processName)s,p:%(process)d,tN:%(threadName)s] %(message)s"
@@ -220,7 +219,7 @@ class GunicornApplicationStack(ApplicationStack):
def log_startup(self):
msg = [f"Galaxy server instance '{self.config.server_name}' is running"]
if "GUNICORN_LISTENERS" in os.environ:
- message = f'\nServing on {os.environ["GUNICORN_LISTENERS"]}\n'
+ message = f"\nServing on {os.environ['GUNICORN_LISTENERS']}\n"
msg.append(f"\033[92m{message}\033[0m") # Highlight in green
log.info("\n".join(msg))
diff --git a/lib/galaxy/web_stack/handlers.py b/lib/galaxy/web_stack/handlers.py
index 0ee037dbf0f..29f726638e8 100644
--- a/lib/galaxy/web_stack/handlers.py
+++ b/lib/galaxy/web_stack/handlers.py
@@ -72,7 +72,7 @@ class ConfiguresHandlers:
self.app = app
self.handler_assignment_methods: list[HANDLER_ASSIGNMENT_METHODS] = []
self.handler_assignment_methods_configured = False
- self.handler_max_grab: Union[int, None] = None
+ self.handler_max_grab: int | None = None
self.handlers: dict[str, list[str]] = {}
def add_handler(self, handler_id: str, tags: list[str]) -> None:
@@ -124,7 +124,7 @@ class ConfiguresHandlers:
return handling_config_dict
- def _init_handlers(self, handling_config_dict: Union[dict, None]) -> None:
+ def _init_handlers(self, handling_config_dict: dict | None) -> None:
handling_config_dict = handling_config_dict or {}
for handler_id, process in handling_config_dict.get("processes", {}).items():
process = process or {}
@@ -139,15 +139,15 @@ class ConfiguresHandlers:
handling_config_dict.get("default"), list(self.handlers.keys()), required=False
)
- def _init_handler_assignment_methods(self, handling_config_dict: Union[dict, None] = None) -> None:
+ def _init_handler_assignment_methods(self, handling_config_dict: dict | None = None) -> None:
handling_config_dict = handling_config_dict or {}
- self.__is_handler: Union[bool, None] = None
+ self.__is_handler: bool | None = None
# This is set by the stack job handler init code
self.pool_for_tag: dict[str, str] = {}
self._handler_assignment_method_methods: dict[
HANDLER_ASSIGNMENT_METHODS,
- Callable[Concatenate[ModelWithHandler, HANDLER_ASSIGNMENT_METHODS, Union[str, None], bool, ...], str],
+ Callable[Concatenate[ModelWithHandler, HANDLER_ASSIGNMENT_METHODS, str | None, bool, ...], str],
] = {
HANDLER_ASSIGNMENT_METHODS.MEM_SELF: self._assign_mem_self_handler,
HANDLER_ASSIGNMENT_METHODS.DB_SELF: self._assign_db_self_handler,
@@ -207,7 +207,7 @@ class ConfiguresHandlers:
def _get_default(
self, config, parent: "Element", names: list[str], auto: bool = False, required: bool = True
- ) -> Union[str, None]:
+ ) -> str | None:
"""
Returns the default attribute set in a parent tag like or
, or return the ID of the child, if there is no explicit
@@ -228,8 +228,8 @@ class ConfiguresHandlers:
return self._ensure_default_set(rval, names, auto=auto, required=required)
def _ensure_default_set(
- self, rval: Union[str, None], names: list[str], auto: bool = False, required: bool = True
- ) -> Union[str, None]:
+ self, rval: str | None, names: list[str], auto: bool = False, required: bool = True
+ ) -> str | None:
if rval is not None:
# If the parent element has a 'default' attribute, use the id or tag in that attribute
if required and rval not in names:
@@ -243,9 +243,7 @@ class ConfiguresHandlers:
return rval
@staticmethod
- def _findall_with_required(
- parent: "Element", match: str, attribs: Union[Iterable[str], None] = None
- ) -> list["Element"]:
+ def _findall_with_required(parent: "Element", match: str, attribs: Iterable[str] | None = None) -> list["Element"]:
"""Like ``lxml.etree.Element.findall()``, except only returns children that have the specified attribs.
:param parent: Parent element in which to find.
@@ -306,7 +304,7 @@ class ConfiguresHandlers:
is_handler = property(_get_is_handler, _set_is_handler)
- def _get_single_item(self, collection: Sequence[T], index: Union[int, None] = None) -> T:
+ def _get_single_item(self, collection: Sequence[T], index: int | None = None) -> T:
"""Given a collection of handlers or destinations, return one item from the collection at random."""
# Done like this to avoid random under the assumption it's faster to avoid it
if len(collection) == 1:
@@ -331,8 +329,8 @@ class ConfiguresHandlers:
# If these get to be any more complex we should probably modularize them, or at least move to a separate class
def _assign_handler_direct(
- self, obj: ModelWithHandler, configured: Union[str, None], flush: bool = True
- ) -> Union[str, Literal[False]]:
+ self, obj: ModelWithHandler, configured: str | None, flush: bool = True
+ ) -> str | Literal[False]:
"""Directly assign a handler if the object has been preconfigured to a known single static handler.
:param obj: Same as :method:`ConfiguresHandlers.assign_handler()`.
@@ -356,7 +354,7 @@ class ConfiguresHandlers:
self,
obj: ModelWithHandler,
method: HANDLER_ASSIGNMENT_METHODS,
- configured: Union[str, None],
+ configured: str | None,
flush: bool,
queue_callback=None,
**kwargs,
@@ -394,7 +392,7 @@ class ConfiguresHandlers:
self,
obj: ModelWithHandler,
method: HANDLER_ASSIGNMENT_METHODS,
- configured: Union[str, None],
+ configured: str | None,
flush: bool,
**kwargs,
) -> str:
@@ -422,9 +420,9 @@ class ConfiguresHandlers:
self,
obj: ModelWithHandler,
method: HANDLER_ASSIGNMENT_METHODS,
- configured: Union[str, None],
+ configured: str | None,
flush: bool,
- index: Union[int, None] = None,
+ index: int | None = None,
**kwargs,
) -> str:
"""Assign object to a handler by setting its ``handler`` column in the database to a handler selected at random
@@ -464,7 +462,7 @@ class ConfiguresHandlers:
self,
obj: ModelWithHandler,
method: HANDLER_ASSIGNMENT_METHODS,
- configured: Union[str, None],
+ configured: str | None,
flush: bool,
**kwargs,
) -> str:
@@ -485,7 +483,7 @@ class ConfiguresHandlers:
_timed_flush_obj(obj)
return handler
- def assign_handler(self, obj: ModelWithHandler, configured: Union[str, None] = None, flush: bool = True, **kwargs):
+ def assign_handler(self, obj: ModelWithHandler, configured: str | None = None, flush: bool = True, **kwargs):
"""Set a job handler, flush obj
Called assignment methods should raise py:class:`HandlerAssignmentSkip` to indicate that the next method
diff --git a/lib/galaxy/web_stack/message.py b/lib/galaxy/web_stack/message.py
index b3af8c03498..44eb57af74e 100644
--- a/lib/galaxy/web_stack/message.py
+++ b/lib/galaxy/web_stack/message.py
@@ -3,9 +3,6 @@
import json
import logging
import types
-from typing import (
- Optional,
-)
log = logging.getLogger(__name__)
@@ -107,7 +104,7 @@ class ApplicationStackMessage(dict):
)
@property
- def target(self) -> Optional[str]:
+ def target(self) -> str | None:
return self["target"]
@target.setter # type: ignore[attr-defined]
diff --git a/lib/galaxy/webapps/base/api.py b/lib/galaxy/webapps/base/api.py
index 67e09128961..056648435ac 100644
--- a/lib/galaxy/webapps/base/api.py
+++ b/lib/galaxy/webapps/base/api.py
@@ -7,7 +7,6 @@ from typing import (
Any,
Optional,
TYPE_CHECKING,
- Union,
)
import anyio
@@ -122,18 +121,18 @@ class GalaxyFileResponse(FileResponse):
database after the response is constructed.
"""
- nginx_x_accel_redirect_base: Optional[str] = None
- apache_xsendfile: Optional[bool] = None
+ nginx_x_accel_redirect_base: str | None = None
+ apache_xsendfile: bool | None = None
def __init__(
self,
path: StrPath,
status_code: int = 200,
- headers: Optional[Mapping[str, str]] = None,
- media_type: Optional[str] = None,
+ headers: Mapping[str, str] | None = None,
+ media_type: str | None = None,
background: Optional["BackgroundTask"] = None,
- filename: Optional[str] = None,
- stat_result: Optional[os.stat_result] = None,
+ filename: str | None = None,
+ stat_result: os.stat_result | None = None,
content_disposition_type: str = "attachment",
) -> None:
super().__init__(
@@ -301,7 +300,7 @@ def get_error_response_for_request(request: Request, exc: MessageException) -> J
else:
content = error_dict
- retry_after: Optional[int] = getattr(exc, "retry_after", None)
+ retry_after: int | None = getattr(exc, "retry_after", None)
headers: dict[str, str] = {}
if retry_after:
headers["Retry-After"] = str(retry_after)
@@ -325,7 +324,6 @@ def add_exception_handler(app: FastAPI) -> None:
class AccessLoggingMiddleware(Plugin):
-
key = "access_line"
async def process_request(self, request):
@@ -369,7 +367,7 @@ def build_route_name_index(app: FastAPI) -> dict[str, list["BaseRoute"]]:
def include_all_package_routers(app: FastAPI, package_name: str):
- responses: dict[Union[int, str], dict[str, Any]] = {
+ responses: dict[int | str, dict[str, Any]] = {
"4XX": {
"description": "Request Error",
"model": MessageExceptionModel,
diff --git a/lib/galaxy/webapps/base/webapp.py b/lib/galaxy/webapps/base/webapp.py
index adb053b0cc2..8e58eee2e69 100644
--- a/lib/galaxy/webapps/base/webapp.py
+++ b/lib/galaxy/webapps/base/webapp.py
@@ -12,7 +12,6 @@ from contextlib import ExitStack
from http.cookies import CookieError
from typing import (
Any,
- Optional,
)
from urllib.parse import urlparse
@@ -111,9 +110,7 @@ class WebApplication(base.WebApplication):
injection_aware: bool = False
- def __init__(
- self, galaxy_app: MinimalApp, session_cookie: str = "galaxysession", name: Optional[str] = None
- ) -> None:
+ def __init__(self, galaxy_app: MinimalApp, session_cookie: str = "galaxysession", name: str | None = None) -> None:
super().__init__()
self.name = name
galaxy_app.is_webapp = True
@@ -319,7 +316,7 @@ class GalaxyWebTransaction(base.DefaultWebTransaction, context.ProvidesHistoryCo
"""
def __init__(
- self, environ: dict[str, Any], app: BasicSharedApp, webapp: WebApplication, session_cookie: Optional[str] = None
+ self, environ: dict[str, Any], app: BasicSharedApp, webapp: WebApplication, session_cookie: str | None = None
) -> None:
self._app = app
self.webapp = webapp
@@ -548,7 +545,7 @@ class GalaxyWebTransaction(base.DefaultWebTransaction, context.ProvidesHistoryCo
if self.app.config.cookie_domain is not None:
self.response.cookies[name]["domain"] = self.app.config.cookie_domain
- def _authenticate_api(self, session_cookie: str) -> Optional[str]:
+ def _authenticate_api(self, session_cookie: str) -> str | None:
"""
Authenticate for the API via key or session (if available).
"""
diff --git a/lib/galaxy/webapps/galaxy/api/__init__.py b/lib/galaxy/webapps/galaxy/api/__init__.py
index bb8ee853fc0..04be79eedaf 100644
--- a/lib/galaxy/webapps/galaxy/api/__init__.py
+++ b/lib/galaxy/webapps/galaxy/api/__init__.py
@@ -14,7 +14,6 @@ from typing import (
cast,
Literal,
NamedTuple,
- Optional,
TypeVar,
)
from urllib.parse import (
@@ -151,7 +150,7 @@ def get_session(
session_manager=cast(GalaxySessionManager, Depends(get_session_manager)),
security: IdEncodingHelper = depends(IdEncodingHelper),
galaxysession: str = Security(api_key_cookie),
-) -> Optional[model.GalaxySession]:
+) -> model.GalaxySession | None:
if galaxysession:
session_key = security.decode_guid(galaxysession)
if session_key:
@@ -165,7 +164,7 @@ def get_api_user(
key: str = Security(api_key_query),
x_api_key: str = Security(api_key_header),
bearer_token: HTTPAuthorizationCredentials = Security(api_bearer_token),
- run_as: Optional[DecodedDatabaseIdField] = Header(
+ run_as: DecodedDatabaseIdField | None = Header(
default=None,
title="Run as User",
description=(
@@ -173,7 +172,7 @@ def get_api_user(
"Only admins and designated users can make API calls on behalf of other users."
),
),
-) -> Optional[User]:
+) -> User | None:
if api_key := key or x_api_key:
user = user_manager.by_api_key(api_key=api_key)
elif bearer_token:
@@ -189,17 +188,17 @@ def get_api_user(
def get_user(
- galaxy_session=cast(Optional[model.GalaxySession], Depends(get_session)),
- api_user=cast(Optional[User], Depends(get_api_user)),
-) -> Optional[User]:
+ galaxy_session=cast(model.GalaxySession | None, Depends(get_session)),
+ api_user=cast(User | None, Depends(get_api_user)),
+) -> User | None:
if galaxy_session:
return galaxy_session.user
return api_user
def get_required_user(
- galaxy_session=cast(Optional[model.GalaxySession], Depends(get_session)),
- api_user=cast(Optional[User], Depends(get_api_user)),
+ galaxy_session=cast(model.GalaxySession | None, Depends(get_session)),
+ api_user=cast(User | None, Depends(get_api_user)),
) -> User:
if galaxy_session and (user := galaxy_session.user):
return user
@@ -267,7 +266,7 @@ class GalaxyASGIRequest(GalaxyAbstractRequest):
def __init__(self, request: Request):
self.__request = request
- self.__environ: Optional[Environ] = None
+ self.__environ: Environ | None = None
@property
def base(self) -> str:
@@ -310,7 +309,7 @@ class GalaxyASGIRequest(GalaxyAbstractRequest):
return self.host
@property
- def remote_addr(self) -> Optional[str]:
+ def remote_addr(self) -> str | None:
# was available in wsgi and is used create_new_session
# not sure what to do here...
return None
@@ -340,13 +339,13 @@ class GalaxyASGIResponse(GalaxyAbstractResponse):
self,
key: str,
value: str = "",
- max_age: Optional[int] = None,
- expires: Optional[int] = None,
+ max_age: int | None = None,
+ expires: int | None = None,
path: str = "/",
- domain: Optional[str] = None,
+ domain: str | None = None,
secure: bool = False,
httponly: bool = False,
- samesite: Optional[Literal["lax", "strict", "none"]] = "lax",
+ samesite: Literal["lax", "strict", "none"] | None = "lax",
) -> None:
"""Set a cookie."""
self.__response.set_cookie(
@@ -365,7 +364,7 @@ class GalaxyASGIResponse(GalaxyAbstractResponse):
DependsOnUser = cast(User, Depends(get_required_user))
-def get_current_history_from_session(galaxy_session: Optional[model.GalaxySession]) -> Optional[model.History]:
+def get_current_history_from_session(galaxy_session: model.GalaxySession | None) -> model.History | None:
if galaxy_session:
return galaxy_session.current_history
return None
@@ -384,8 +383,8 @@ def get_trans(
request: Request,
response: Response,
app: StructuredApp = DependsOnApp,
- user=cast(Optional[User], Depends(get_user)),
- galaxy_session=cast(Optional[model.GalaxySession], Depends(get_session)),
+ user=cast(User | None, Depends(get_user)),
+ galaxy_session=cast(model.GalaxySession | None, Depends(get_session)),
) -> SessionRequestContext:
url_builder = UrlBuilder(request)
galaxy_request = GalaxyASGIRequest(request)
@@ -449,7 +448,7 @@ class FrameworkRouter(APIRouter):
admin_user_dependency: Any
- def wrap_with_alias(self, verb: RestVerb, *args, alias: Optional[str] = None, **kwd):
+ def wrap_with_alias(self, verb: RestVerb, *args, alias: str | None = None, **kwd):
"""
Wraps FastAPI methods with additional alias keyword, require_admin and CORS handling.
@@ -478,7 +477,6 @@ class FrameworkRouter(APIRouter):
)
if allow_cors:
-
dependencies = kwd.pop("dependencies", [])
dependencies.append(CORSPreflightRequired)
@@ -510,7 +508,7 @@ class FrameworkRouter(APIRouter):
return dec
@staticmethod
- def construct_aliases(path: str, alias: Optional[str]):
+ def construct_aliases(path: str, alias: str | None):
yield path
if path != "/" and not path.endswith("/"):
yield f"{path}/"
@@ -679,7 +677,7 @@ def json_schema_response_for_tool_state_model(
return Response(content=json_str, media_type="application/json")
-async def try_get_request_body_as_json(request: Request) -> Optional[Any]:
+async def try_get_request_body_as_json(request: Request) -> Any | None:
"""Returns the request body as a JSON object if the content type is JSON."""
if "application/json" in request.headers.get("content-type", ""):
body = await request.json()
@@ -718,7 +716,7 @@ ${model_name}s: ${freetext}.
class IndexQueryTag(NamedTuple):
tag: str
description: str
- alias: Optional[str] = None
+ alias: str | None = None
admin_only: bool = False
def as_markdown(self):
@@ -730,7 +728,7 @@ class IndexQueryTag(NamedTuple):
return f"`{self.tag}`\n: {desc}"
-def search_query_param(model_name: str, tags: list, free_text_fields: list) -> Optional[str]:
+def search_query_param(model_name: str, tags: list, free_text_fields: list) -> str | None:
tags_markdown_str = "\n\n".join([t.as_markdown() for t in tags])
description = search_description_template.safe_substitute(
model_name=model_name, tags=tags_markdown_str, freetext=", ".join([f"`{t}`" for t in free_text_fields])
diff --git a/lib/galaxy/webapps/galaxy/api/agents.py b/lib/galaxy/webapps/galaxy/api/agents.py
index c827ec55277..637f938c11d 100644
--- a/lib/galaxy/webapps/galaxy/api/agents.py
+++ b/lib/galaxy/webapps/galaxy/api/agents.py
@@ -5,7 +5,6 @@ import time
from functools import partial
from typing import (
Any,
- Optional,
)
import anyio
@@ -127,11 +126,9 @@ class AgentAPI:
async def analyze_error(
self,
query: str = Body(..., description="Description of the error or problem"),
- job_id: Optional[DecodedDatabaseIdField] = Body(None, description="Job ID for context"),
- error_details: Optional[dict[str, Any]] = Body(None, description="Additional error details"),
- save_exchange: Optional[bool] = Body(
- None, description="Save exchange for feedback tracking. Defaults to false."
- ),
+ job_id: DecodedDatabaseIdField | None = Body(None, description="Job ID for context"),
+ error_details: dict[str, Any] | None = Body(None, description="Additional error details"),
+ save_exchange: bool | None = Body(None, description="Save exchange for feedback tracking. Defaults to false."),
trans: ProvidesUserContext = DependsOnTrans,
user: User = DependsOnUser,
) -> AgentResponse:
@@ -182,10 +179,8 @@ class AgentAPI:
async def create_custom_tool(
self,
query: str = Body(..., description="Description of the tool to create"),
- context: Optional[dict[str, Any]] = Body(None, description="Additional context for tool creation"),
- save_exchange: Optional[bool] = Body(
- None, description="Save exchange for feedback tracking. Defaults to false."
- ),
+ context: dict[str, Any] | None = Body(None, description="Additional context for tool creation"),
+ save_exchange: bool | None = Body(None, description="Save exchange for feedback tracking. Defaults to false."),
trans: ProvidesUserContext = DependsOnTrans,
user: User = DependsOnUser,
) -> AgentResponse:
diff --git a/lib/galaxy/webapps/galaxy/api/chat.py b/lib/galaxy/webapps/galaxy/api/chat.py
index bc257eaf51a..cef6d5ce473 100644
--- a/lib/galaxy/webapps/galaxy/api/chat.py
+++ b/lib/galaxy/webapps/galaxy/api/chat.py
@@ -9,8 +9,6 @@ from functools import partial
from typing import (
Annotated,
Any,
- Optional,
- Union,
)
import anyio
@@ -93,7 +91,7 @@ Please only say that something went wrong when configuring the ai prompt in your
"""
JobIdQueryParam = Annotated[
- Optional[DecodedDatabaseIdField],
+ DecodedDatabaseIdField | None,
Field(
default=None,
title="Job ID",
@@ -122,14 +120,14 @@ class ChatAPI:
@router.post("/api/chat", unstable=True)
async def query(
self,
- job_id: Optional[
+ job_id: (
Annotated[
- DecodedDatabaseIdField,
- Query(title="Job ID", description="The Job ID for backwards compatibility"),
+ DecodedDatabaseIdField, Query(title="Job ID", description="The Job ID for backwards compatibility")
]
- ] = None,
- payload: Optional[ChatPayload] = None,
- query: Optional[str] = Query(default=None, description="Query string for general chat"),
+ | None
+ ) = None,
+ payload: ChatPayload | None = None,
+ query: str | None = Query(default=None, description="Query string for general chat"),
agent_type: str = Query(default="auto", description="Agent type to use for the query"),
trans: ProvidesUserContext = DependsOnTrans,
user: User = DependsOnUser,
@@ -399,7 +397,7 @@ class ChatAPI:
feedback: int,
trans: ProvidesUserContext = DependsOnTrans,
user: User = DependsOnUser,
- ) -> Union[int, None]:
+ ) -> int | None:
"""Provide feedback on the chatbot response."""
job = self.job_manager.get_accessible_job(trans, job_id)
chat_response = self.chat_manager.set_feedback_for_job(trans, job.id, feedback)
@@ -409,7 +407,7 @@ class ChatAPI:
async def generate_report(
self,
workflow_id: str = Path(..., description="Workflow ID to generate the report for"),
- version: Optional[int] = Query(None, description="Version of the workflow"),
+ version: int | None = Query(None, description="Version of the workflow"),
instance: bool = Query(False, description="Whether the workflow_id is an instance ID"),
trans: ProvidesUserContext = DependsOnTrans,
user: User = DependsOnUser,
@@ -505,7 +503,7 @@ class ChatAPI:
if self.config.ai_api_key is None:
raise ConfigurationError("AI API key is not configured for this instance.")
- async def _get_ai_response(self, query: str, trans: ProvidesUserContext, context_type: Optional[str] = None) -> str:
+ async def _get_ai_response(self, query: str, trans: ProvidesUserContext, context_type: str | None = None) -> str:
"""Get response from AI using pydantic-ai Agent"""
system_prompt = self._get_system_prompt()
username = trans.user.username if trans.user else "Anonymous User"
@@ -568,7 +566,7 @@ class ChatAPI:
trans: ProvidesUserContext,
user: User,
job=None,
- context: Optional[dict[str, Any]] = None,
+ context: dict[str, Any] | None = None,
) -> str:
"""Get response using the new agent system (legacy method for compatibility)."""
result = await self._get_agent_response_full(query, agent_type, trans, user, job, context)
@@ -581,7 +579,7 @@ class ChatAPI:
trans: ProvidesUserContext,
user: User,
job=None,
- context: Optional[dict[str, Any]] = None,
+ context: dict[str, Any] | None = None,
) -> AgentResponse:
"""Get full agent response with metadata and suggestions."""
# Prepare context - merge passed context with job context
diff --git a/lib/galaxy/webapps/galaxy/api/common.py b/lib/galaxy/webapps/galaxy/api/common.py
index d75f618becc..b6cdd0dcb6e 100644
--- a/lib/galaxy/webapps/galaxy/api/common.py
+++ b/lib/galaxy/webapps/galaxy/api/common.py
@@ -4,7 +4,6 @@ from io import BytesIO
from typing import (
Annotated,
Any,
- Optional,
)
from fastapi import (
@@ -119,48 +118,48 @@ QuotaIdPathParam = Annotated[
]
SerializationViewQueryParam = Annotated[
- Optional[str],
+ str | None,
Query(
title="View",
description="View to be passed to the serializer",
),
]
-SerializationKeysQueryParam: Optional[str] = Query(
+SerializationKeysQueryParam: str | None = Query(
None,
title="Keys",
description="Comma-separated list of keys to be passed to the serializer",
)
-FilterQueryQueryParam: Optional[list[str]] = Query(
+FilterQueryQueryParam: list[str] | None = Query(
default=None,
title="Filter Query",
description="Generally a property name to filter by followed by an (often optional) hyphen and operator string.",
examples=["create_time-gt"],
)
-FilterValueQueryParam: Optional[list[str]] = Query(
+FilterValueQueryParam: list[str] | None = Query(
default=None,
title="Filter Value",
description="The value to filter by.",
examples=["2015-01-29"],
)
-OffsetQueryParam: Optional[int] = Query(
+OffsetQueryParam: int | None = Query(
default=0,
ge=0,
title="Offset",
description="Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item",
)
-LimitQueryParam: Optional[int] = Query(
+LimitQueryParam: int | None = Query(
default=None,
ge=1,
title="Limit",
description="The maximum number of items to return.",
)
-OrderQueryParam: Optional[str] = Query(
+OrderQueryParam: str | None = Query(
default=None,
title="Order",
description=(
@@ -172,9 +171,9 @@ OrderQueryParam: Optional[str] = Query(
def parse_serialization_params(
- view: Optional[str] = None,
- keys: Optional[str] = None,
- default_view: Optional[str] = None,
+ view: str | None = None,
+ keys: str | None = None,
+ default_view: str | None = None,
**_, # Additional params are ignored
) -> SerializationParams:
key_list = None
@@ -185,14 +184,14 @@ def parse_serialization_params(
def query_serialization_params(
view: SerializationViewQueryParam = None,
- keys: Optional[str] = SerializationKeysQueryParam,
+ keys: str | None = SerializationKeysQueryParam,
) -> SerializationParams:
return parse_serialization_params(view=view, keys=keys)
def get_value_filter_query_params(
- q: Optional[list[str]] = FilterQueryQueryParam,
- qv: Optional[list[str]] = FilterValueQueryParam,
+ q: list[str] | None = FilterQueryQueryParam,
+ qv: list[str] | None = FilterValueQueryParam,
) -> ValueFilterQueryParams:
"""
This function is meant to be used as a Dependency.
@@ -205,11 +204,11 @@ def get_value_filter_query_params(
def get_filter_query_params(
- q: Optional[list[str]] = FilterQueryQueryParam,
- qv: Optional[list[str]] = FilterValueQueryParam,
- offset: Optional[int] = OffsetQueryParam,
- limit: Optional[int] = LimitQueryParam,
- order: Optional[str] = OrderQueryParam,
+ q: list[str] | None = FilterQueryQueryParam,
+ qv: list[str] | None = FilterValueQueryParam,
+ offset: int | None = OffsetQueryParam,
+ limit: int | None = LimitQueryParam,
+ order: str | None = OrderQueryParam,
) -> FilterQueryParams:
"""
This function is meant to be used as a Dependency.
@@ -286,8 +285,8 @@ def query_parameter_as_list(query):
"""
def parse_elements(
- elements: Optional[list[str]] = query,
- ) -> Optional[list[Any]]:
+ elements: list[str] | None = query,
+ ) -> list[Any] | None:
if query.default != Ellipsis and not elements:
return query.default
if elements and len(elements) == 1:
@@ -297,7 +296,7 @@ def query_parameter_as_list(query):
return parse_elements
-def serve_workbook(content: BytesIO, filename: Optional[str]) -> StreamingResponse:
+def serve_workbook(content: BytesIO, filename: str | None) -> StreamingResponse:
filename = filename or "galaxy_sample_sheet_workbook.xlsx"
return GalaxyStreamingResponse(
content,
diff --git a/lib/galaxy/webapps/galaxy/api/configuration.py b/lib/galaxy/webapps/galaxy/api/configuration.py
index 18843642b3a..8256c5dd0aa 100644
--- a/lib/galaxy/webapps/galaxy/api/configuration.py
+++ b/lib/galaxy/webapps/galaxy/api/configuration.py
@@ -6,7 +6,6 @@ and configuration settings.
import logging
from typing import (
Any,
- Optional,
)
from fastapi import Path
@@ -53,7 +52,7 @@ class FastAPIConfiguration:
summary="Return information about the current authenticated user",
response_description="Information about the current authenticated user",
)
- def whoami(self, trans: ProvidesUserContext = DependsOnTrans) -> Optional[UserModel]:
+ def whoami(self, trans: ProvidesUserContext = DependsOnTrans) -> UserModel | None:
"""Return information about the current authenticated user."""
return _user_to_model(trans.user)
@@ -66,7 +65,7 @@ class FastAPIConfiguration:
self,
trans: ProvidesUserContext = DependsOnTrans,
view: SerializationViewQueryParam = None,
- keys: Optional[str] = SerializationKeysQueryParam,
+ keys: str | None = SerializationKeysQueryParam,
) -> dict[str, Any]:
"""
Return an object containing exposable configuration settings.
diff --git a/lib/galaxy/webapps/galaxy/api/context.py b/lib/galaxy/webapps/galaxy/api/context.py
index 006f5f52014..ec840452a1e 100644
--- a/lib/galaxy/webapps/galaxy/api/context.py
+++ b/lib/galaxy/webapps/galaxy/api/context.py
@@ -1,7 +1,6 @@
import logging
from typing import (
Any,
- Optional,
)
from galaxy.managers.configuration import ConfigurationManager
@@ -22,7 +21,7 @@ router = Router(tags=["context"])
class ContextResponse(Model):
config: dict[str, Any]
- session_csrf_token: Optional[str] = None
+ session_csrf_token: str | None = None
user: dict[str, Any]
diff --git a/lib/galaxy/webapps/galaxy/api/credentials.py b/lib/galaxy/webapps/galaxy/api/credentials.py
index caa30a80336..5a1753b7d57 100644
--- a/lib/galaxy/webapps/galaxy/api/credentials.py
+++ b/lib/galaxy/webapps/galaxy/api/credentials.py
@@ -3,10 +3,6 @@ API operations on credentials (credentials and variables).
"""
import logging
-from typing import (
- Optional,
- Union,
-)
from fastapi import (
Query,
@@ -50,15 +46,15 @@ class FastAPICredentials:
self,
user_id: FlexibleUserIdType,
trans: ProvidesUserContext = DependsOnTrans,
- source_type: Optional[SOURCE_TYPE] = Query(
+ source_type: SOURCE_TYPE | None = Query(
None,
description="The type of source to filter by.",
),
- source_id: Optional[str] = Query(
+ source_id: str | None = Query(
None,
description="The ID of the source to filter by.",
),
- source_version: Optional[str] = Query(
+ source_version: str | None = Query(
None,
description="The version of the source to filter by. By default it is the latest version.",
),
@@ -66,7 +62,7 @@ class FastAPICredentials:
False,
description="Whether to include extended credential definition information.",
),
- ) -> Union[UserServiceCredentialsListResponse, ExtendedUserCredentialsListResponse]:
+ ) -> UserServiceCredentialsListResponse | ExtendedUserCredentialsListResponse:
return self.service.list_user_credentials(
trans, user_id, source_type, source_id, source_version, include_definition
)
diff --git a/lib/galaxy/webapps/galaxy/api/dataset_collections.py b/lib/galaxy/webapps/galaxy/api/dataset_collections.py
index 522f6a44f66..00b3b052ee0 100644
--- a/lib/galaxy/webapps/galaxy/api/dataset_collections.py
+++ b/lib/galaxy/webapps/galaxy/api/dataset_collections.py
@@ -1,7 +1,6 @@
from logging import getLogger
from typing import (
Annotated,
- Optional,
)
from fastapi import (
@@ -71,7 +70,7 @@ Base64PrefixValuesQueryParam: str = Query(
None,
description="Prefix values for the seeding the workbook, base64 encoded.",
)
-WorkbookFilenameQueryParam: Optional[str] = Query(
+WorkbookFilenameQueryParam: str | None = Query(
None,
description="Filename of the workbook download to generate",
)
@@ -101,7 +100,7 @@ class FastAPIDatasetCollections:
def create_workbook(
self,
trans: ProvidesHistoryContext = DependsOnTrans,
- filename: Optional[str] = WorkbookFilenameQueryParam,
+ filename: str | None = WorkbookFilenameQueryParam,
payload: CreateWorkbookRequest = Body(...),
):
output = self.service.create_workbook(payload)
@@ -129,7 +128,7 @@ class FastAPIDatasetCollections:
self,
hdca_id: HistoryHDCAIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- filename: Optional[str] = WorkbookFilenameQueryParam,
+ filename: str | None = WorkbookFilenameQueryParam,
payload: CreateWorkbookForCollectionApi = Body(...),
):
output = self.service.create_workbook_for_collection(trans, hdca_id, payload)
@@ -216,11 +215,11 @@ class FastAPIDatasetCollections:
],
trans: ProvidesHistoryContext = DependsOnTrans,
instance_type: DatasetCollectionInstanceType = InstanceTypeQueryParam,
- limit: Optional[int] = Query(
+ limit: int | None = Query(
default=None,
description="The maximum number of content elements to return.",
),
- offset: Optional[int] = Query(
+ offset: int | None = Query(
default=None,
description="The number of content elements that will be skipped before returning.",
),
diff --git a/lib/galaxy/webapps/galaxy/api/datasets.py b/lib/galaxy/webapps/galaxy/api/datasets.py
index 61ad649cef8..c68d1ec45ae 100644
--- a/lib/galaxy/webapps/galaxy/api/datasets.py
+++ b/lib/galaxy/webapps/galaxy/api/datasets.py
@@ -11,7 +11,6 @@ from io import (
from typing import (
Annotated,
cast,
- Optional,
)
from fastapi import (
@@ -149,7 +148,7 @@ class FastAPIDatasets:
self,
response: Response,
trans=DependsOnTrans,
- history_id: Optional[DecodedDatabaseIdField] = Query(
+ history_id: DecodedDatabaseIdField | None = Query(
default=None,
description="Optional identifier of a History. Use it to restrict the search within a particular History.",
),
@@ -192,7 +191,7 @@ class FastAPIDatasets:
def get_content_as_text(
self,
dataset_id: HistoryDatasetIDPathParam,
- filename: Optional[str] = FilenameQueryParam,
+ filename: str | None = FilenameQueryParam,
trans=DependsOnTrans,
) -> DatasetTextContentDetails:
return self.service.get_content_as_text(trans, dataset_id, filename=filename)
@@ -312,14 +311,14 @@ class FastAPIDatasets:
self,
request: Request,
history_content_id: HistoryDatasetIDPathParam,
- history_id: Optional[HistoryIDPathParam] = None,
+ history_id: HistoryIDPathParam | None = None,
trans=DependsOnTrans,
preview: bool = PreviewQueryParam,
- filename: Optional[str] = FilenameQueryParam,
- to_ext: Optional[str] = ToExtQueryParam,
+ filename: str | None = FilenameQueryParam,
+ to_ext: str | None = ToExtQueryParam,
raw: bool = RawQueryParam,
- offset: Optional[int] = DisplayOffsetQueryParam,
- ck_size: Optional[int] = DisplayChunkSizeQueryParam,
+ offset: int | None = DisplayOffsetQueryParam,
+ ck_size: int | None = DisplayChunkSizeQueryParam,
):
"""Streams the dataset for download or the contents preview to be displayed in a browser."""
return self._display(request, trans, history_content_id, preview, filename, to_ext, raw, offset, ck_size)
@@ -339,11 +338,11 @@ class FastAPIDatasets:
history_content_id: HistoryDatasetIDPathParam,
trans=DependsOnTrans,
preview: bool = PreviewQueryParam,
- filename: Optional[str] = FilenameQueryParam,
- to_ext: Optional[str] = ToExtQueryParam,
+ filename: str | None = FilenameQueryParam,
+ to_ext: str | None = ToExtQueryParam,
raw: bool = RawQueryParam,
- offset: Optional[int] = DisplayOffsetQueryParam,
- ck_size: Optional[int] = DisplayChunkSizeQueryParam,
+ offset: int | None = DisplayOffsetQueryParam,
+ ck_size: int | None = DisplayChunkSizeQueryParam,
):
"""Streams the dataset for download or the contents preview to be displayed in a browser."""
return self._display(request, trans, history_content_id, preview, filename, to_ext, raw, offset, ck_size)
@@ -354,11 +353,11 @@ class FastAPIDatasets:
trans,
history_content_id: DecodedDatabaseIdField,
preview: bool,
- filename: Optional[str],
- to_ext: Optional[str],
+ filename: str | None,
+ to_ext: str | None,
raw: bool,
- offset: Optional[int] = None,
- ck_size: Optional[int] = None,
+ offset: int | None = None,
+ ck_size: int | None = None,
):
extra_params = get_query_parameters_from_request_excluding(
request, {"preview", "filename", "to_ext", "raw", "dataset", "ck_size", "offset"}
@@ -449,7 +448,7 @@ class FastAPIDatasets:
default=DatasetSourceType.hda,
description=("The type of information about the dataset to be requested."),
),
- data_type: Optional[RequestDataType] = Query(
+ data_type: RequestDataType | None = Query(
default=None,
description=(
"The type of information about the dataset to be requested. "
@@ -458,7 +457,7 @@ class FastAPIDatasets:
),
),
limit: Annotated[
- Optional[int],
+ int | None,
Query(
ge=1,
le=MAX_LIMIT,
@@ -466,7 +465,7 @@ class FastAPIDatasets:
),
] = MAX_LIMIT,
offset: Annotated[
- Optional[int],
+ int | None,
Query(
ge=0,
description="Starts at the beginning skip the first ( offset - 1 ) items and begin returning at the Nth item. Currently only applies to `data_type=raw_data` requests",
diff --git a/lib/galaxy/webapps/galaxy/api/datatypes.py b/lib/galaxy/webapps/galaxy/api/datatypes.py
index 470d292c8a5..25697528a9b 100644
--- a/lib/galaxy/webapps/galaxy/api/datatypes.py
+++ b/lib/galaxy/webapps/galaxy/api/datatypes.py
@@ -5,8 +5,6 @@ API operations allowing clients to determine datatype supported by Galaxy.
import logging
from typing import (
cast,
- Optional,
- Union,
)
from fastapi import (
@@ -44,19 +42,19 @@ log = logging.getLogger(__name__)
router = Router(tags=["datatypes"])
-ExtensionOnlyQueryParam: Optional[bool] = Query(
+ExtensionOnlyQueryParam: bool | None = Query(
default=True,
title="Extension only",
description="Whether to return only the datatype's extension rather than the datatype's details",
)
-UploadOnlyQueryParam: Optional[bool] = Query(
+UploadOnlyQueryParam: bool | None = Query(
default=True,
title="Upload only",
description="Whether to return only datatypes which can be uploaded",
)
-IdentifierOnly: Optional[bool] = Query(
+IdentifierOnly: bool | None = Query(
default=True,
title="prefixIRI only",
description="Whether to return only the EDAM prefixIRI rather than the EDAM details",
@@ -76,9 +74,9 @@ class FastAPIDatatypes:
)
async def index(
self,
- extension_only: Optional[bool] = ExtensionOnlyQueryParam,
- upload_only: Optional[bool] = UploadOnlyQueryParam,
- ) -> Union[list[DatatypeDetails], list[str]]:
+ extension_only: bool | None = ExtensionOnlyQueryParam,
+ upload_only: bool | None = UploadOnlyQueryParam,
+ ) -> list[DatatypeDetails] | list[str]:
"""Gets the list of all available data types."""
return view_index(self.datatypes_registry, extension_only, upload_only)
@@ -100,8 +98,8 @@ class FastAPIDatatypes:
)
async def types_and_mapping(
self,
- extension_only: Optional[bool] = ExtensionOnlyQueryParam,
- upload_only: Optional[bool] = UploadOnlyQueryParam,
+ extension_only: bool | None = ExtensionOnlyQueryParam,
+ upload_only: bool | None = UploadOnlyQueryParam,
) -> DatatypesCombinedMap:
"""Combines the datatype information from (/api/datatypes) and the
mapping information from (/api/datatypes/mapping) into a single
diff --git a/lib/galaxy/webapps/galaxy/api/display_applications.py b/lib/galaxy/webapps/galaxy/api/display_applications.py
index cfba6d732f2..186ffc7fdf7 100644
--- a/lib/galaxy/webapps/galaxy/api/display_applications.py
+++ b/lib/galaxy/webapps/galaxy/api/display_applications.py
@@ -3,7 +3,6 @@ API operations on annotations.
"""
import logging
-from typing import Optional
from fastapi import Body
@@ -78,7 +77,7 @@ class FastAPIDisplayApplications:
)
def reload(
self,
- payload: Optional[dict[str, list[str]]] = Body(default=None),
+ payload: dict[str, list[str]] | None = Body(default=None),
) -> ReloadFeedback:
"""
Reloads the list of display applications.
diff --git a/lib/galaxy/webapps/galaxy/api/dynamic_tools.py b/lib/galaxy/webapps/galaxy/api/dynamic_tools.py
index 011c743ca5f..091a908b693 100644
--- a/lib/galaxy/webapps/galaxy/api/dynamic_tools.py
+++ b/lib/galaxy/webapps/galaxy/api/dynamic_tools.py
@@ -3,8 +3,6 @@ from datetime import datetime
from typing import (
Any,
Literal,
- Optional,
- Union,
)
from fastapi import Response
@@ -50,7 +48,7 @@ log = logging.getLogger(__name__)
router = Router(tags=["dynamic_tools"])
-DatabaseIdOrUUID = Union[DecodedDatabaseIdField, str]
+DatabaseIdOrUUID = DecodedDatabaseIdField | str
def _set_lift_headers(response: Response, status: str, errors: list[str]) -> None:
@@ -74,12 +72,12 @@ class UnprivilegedToolResponse(BaseModel):
uuid: str
active: bool
hidden: bool
- tool_id: Optional[str]
- tool_format: Optional[str]
+ tool_id: str | None
+ tool_format: str | None
create_time: datetime
# Either a strict UserToolSource (status="ok" or "lifted") or the raw
# stored dict (status="invalid"). Consumers narrow on `representation_status`.
- representation: Union[UserToolSource, dict[str, Any]]
+ representation: UserToolSource | dict[str, Any]
representation_status: Literal["ok", "lifted", "invalid"] = "ok"
representation_errors: list[str] = []
@@ -201,7 +199,7 @@ class DynamicToolApi:
return [t.to_dict() for t in self.dynamic_tools_manager.list_tools()]
@router.get("/api/dynamic_tools/{dynamic_tool_id}", public=True)
- def show(self, dynamic_tool_id: Union[DatabaseIdOrUUID, str]):
+ def show(self, dynamic_tool_id: DatabaseIdOrUUID | str):
dynamic_tool = self.dynamic_tools_manager.get_tool_by_id_or_uuid(dynamic_tool_id)
if dynamic_tool is None:
raise ObjectNotFound()
diff --git a/lib/galaxy/webapps/galaxy/api/events.py b/lib/galaxy/webapps/galaxy/api/events.py
index 33cb20ec61c..d30f3410aa9 100644
--- a/lib/galaxy/webapps/galaxy/api/events.py
+++ b/lib/galaxy/webapps/galaxy/api/events.py
@@ -6,7 +6,6 @@ history updates, etc.) independent of the notification system configuration.
"""
import logging
-from typing import Optional
from fastapi import (
Body,
@@ -51,7 +50,7 @@ class FastAPIEvents:
self,
request: Request,
trans: ProvidesUserContext = DependsOnTrans,
- last_event_id: Optional[str] = Header(None, alias="Last-Event-ID"),
+ last_event_id: str | None = Header(None, alias="Last-Event-ID"),
) -> StreamingResponse:
"""Opens a Server-Sent Events (SSE) connection that pushes real-time
updates for notifications, history changes, and other events.
diff --git a/lib/galaxy/webapps/galaxy/api/exports.py b/lib/galaxy/webapps/galaxy/api/exports.py
index 67fc23eedb3..01428d3e4ee 100644
--- a/lib/galaxy/webapps/galaxy/api/exports.py
+++ b/lib/galaxy/webapps/galaxy/api/exports.py
@@ -6,8 +6,6 @@ import json
import logging
from typing import (
Annotated,
- Optional,
- Union,
)
from uuid import UUID
@@ -48,7 +46,7 @@ class FastAPIExports:
self,
trans: ProvidesUserContext = DependsOnTrans,
limit: Annotated[
- Optional[int],
+ int | None,
Query(
title="Limit",
description="Maximum number of exports to return.",
@@ -95,7 +93,7 @@ class FastAPIExports:
return ExportTaskListResponse(root=results)
- def _parse_export_metadata(self, metadata: Union[dict, str]) -> Optional[ExportObjectMetadata]:
+ def _parse_export_metadata(self, metadata: dict | str) -> ExportObjectMetadata | None:
"""Parse export metadata dict without double-encoding ID fields.
We use model_construct() to skip Pydantic validation because the ID fields
@@ -106,13 +104,12 @@ class FastAPIExports:
metadata = json.loads(metadata)
assert isinstance(metadata, dict)
request_data_raw = metadata.get("request_data", {})
- result_data_raw = metadata.get("result_data")
payload_raw = request_data_raw.get("payload") or {}
# Pick the right payload flavour by presence of target_uri
# (WriteStoreToPayload has it, ShortTermStoreExportPayload does not).
if "target_uri" in payload_raw:
- payload: Union[WriteStoreToPayload, ShortTermStoreExportPayload] = WriteStoreToPayload.model_construct(
+ payload: WriteStoreToPayload | ShortTermStoreExportPayload = WriteStoreToPayload.model_construct(
**payload_raw
)
else:
@@ -131,7 +128,7 @@ class FastAPIExports:
)
result_data = None
- if result_data_raw:
+ if result_data_raw := metadata.get("result_data"):
result_data = ExportObjectResultMetadata.model_construct(
success=result_data_raw.get("success"),
uri=result_data_raw.get("uri"),
diff --git a/lib/galaxy/webapps/galaxy/api/extended_metadata.py b/lib/galaxy/webapps/galaxy/api/extended_metadata.py
index 273519a00cd..78faa6fdcb1 100644
--- a/lib/galaxy/webapps/galaxy/api/extended_metadata.py
+++ b/lib/galaxy/webapps/galaxy/api/extended_metadata.py
@@ -5,7 +5,6 @@ API operations on annotations.
import logging
from typing import (
Generic,
- Optional,
TypeVar,
)
@@ -34,7 +33,7 @@ class BaseExtendedMetadataController(
):
exmeta_item_id: str
- def _get_item_from_id(self, trans, idstr, check_writable=True) -> Optional[T]: ...
+ def _get_item_from_id(self, trans, idstr, check_writable=True) -> T | None: ...
@web.expose_api
def index(self, trans, **kwd):
@@ -62,7 +61,7 @@ class LibraryDatasetExtendMetadataController(BaseExtendedMetadataController[mode
controller_name = "library_dataset_extended_metadata"
exmeta_item_id = "library_content_id"
- def _get_item_from_id(self, trans, idstr, check_writable=True) -> Optional[model.LibraryDatasetDatasetAssociation]:
+ def _get_item_from_id(self, trans, idstr, check_writable=True) -> model.LibraryDatasetDatasetAssociation | None:
if check_writable:
item = self.get_library_dataset_dataset_association(trans, idstr)
if trans.app.security_agent.can_modify_library_item(trans.get_current_user_roles(), item):
@@ -79,7 +78,7 @@ class HistoryDatasetExtendMetadataController(BaseExtendedMetadataController[mode
exmeta_item_id = "history_content_id"
hda_manager: managers.hdas.HDAManager = depends(managers.hdas.HDAManager)
- def _get_item_from_id(self, trans, idstr, check_writable=True) -> Optional[model.HistoryDatasetAssociation]:
+ def _get_item_from_id(self, trans, idstr, check_writable=True) -> model.HistoryDatasetAssociation | None:
decoded_idstr = self.decode_id(idstr)
if check_writable:
return self.hda_manager.get_owned(decoded_idstr, trans.user, current_history=trans.history)
diff --git a/lib/galaxy/webapps/galaxy/api/folder_contents.py b/lib/galaxy/webapps/galaxy/api/folder_contents.py
index ca9d1bc8ef0..dcc9094476d 100644
--- a/lib/galaxy/webapps/galaxy/api/folder_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/folder_contents.py
@@ -3,7 +3,6 @@ API operations on the contents of a library folder.
"""
import logging
-from typing import Optional
from fastapi import (
Body,
@@ -38,13 +37,13 @@ OffsetQueryParam: int = Query(
description="Return contents from this specified position. For example, if ``limit`` is set to 100 and ``offset`` to 200, contents between position 200-299 will be returned.",
)
-SearchQueryParam: Optional[str] = Query(
+SearchQueryParam: str | None = Query(
default=None,
title="Search Text",
description="Used to filter the contents. Only the folders and files which name contains this text will be returned.",
)
-IncludeDeletedQueryParam: Optional[bool] = Query(
+IncludeDeletedQueryParam: bool | None = Query(
default=False,
title="Include Deleted",
description="Returns also deleted contents. Deleted contents can only be retrieved by Administrators or users with",
@@ -56,7 +55,7 @@ SortByQueryParam: LibraryFolderContentsIndexSortByEnum = Query(
description="Sort results by specified field.",
)
-SortDescQueryParam: Optional[bool] = Query(
+SortDescQueryParam: bool | None = Query(
default=False,
title="Sort Descending",
description="Sort results in descending order.",
@@ -83,10 +82,10 @@ class FastAPILibraryFoldersContents:
trans: ProvidesUserContext = DependsOnTrans,
limit: int = LimitQueryParam,
offset: int = OffsetQueryParam,
- search_text: Optional[str] = SearchQueryParam,
- include_deleted: Optional[bool] = IncludeDeletedQueryParam,
+ search_text: str | None = SearchQueryParam,
+ include_deleted: bool | None = IncludeDeletedQueryParam,
order_by: LibraryFolderContentsIndexSortByEnum = SortByQueryParam,
- sort_desc: Optional[bool] = SortDescQueryParam,
+ sort_desc: bool | None = SortDescQueryParam,
):
"""Returns a list of a folder's contents (files and sub-folders).
diff --git a/lib/galaxy/webapps/galaxy/api/folders.py b/lib/galaxy/webapps/galaxy/api/folders.py
index ffdebf931ee..71d815c0ae5 100644
--- a/lib/galaxy/webapps/galaxy/api/folders.py
+++ b/lib/galaxy/webapps/galaxy/api/folders.py
@@ -5,8 +5,6 @@ API operations on library folders.
import logging
from typing import (
Annotated,
- Optional,
- Union,
)
from fastapi import (
@@ -38,7 +36,7 @@ log = logging.getLogger(__name__)
router = Router(tags=["data libraries folders"])
UndeleteQueryParam = Annotated[
- Optional[bool], Query(title="Undelete", description="Whether to restore a deleted library folder.")
+ bool | None, Query(title="Undelete", description="Whether to restore a deleted library folder.")
]
@@ -106,7 +104,7 @@ class FastAPILibraryFolders:
self,
id: FolderIdPathParam,
trans: ProvidesUserContext = DependsOnTrans,
- scope: Optional[LibraryPermissionScope] = Query(
+ scope: LibraryPermissionScope | None = Query(
None,
title="Scope",
description="The scope of the permissions to retrieve. Either the `current` permissions or the `available`.",
@@ -117,10 +115,10 @@ class FastAPILibraryFolders:
page_limit: int = Query(
default=10, title="Page Limit", description="The maximum number of permissions per page when paginating."
),
- q: Optional[str] = Query(
+ q: str | None = Query(
None, title="Query", description="Optional search text to retrieve only the roles matching this query."
),
- ) -> Union[LibraryFolderCurrentPermissions, LibraryAvailablePermissions]:
+ ) -> LibraryFolderCurrentPermissions | LibraryAvailablePermissions:
"""Gets the current or available permissions of a particular library.
The results can be paginated and additionally filtered by a query."""
return self.service.get_permissions(
@@ -140,7 +138,7 @@ class FastAPILibraryFolders:
self,
id: FolderIdPathParam,
trans: ProvidesUserContext = DependsOnTrans,
- action: Optional[LibraryFolderPermissionAction] = Query(
+ action: LibraryFolderPermissionAction | None = Query(
default=None,
title="Action",
description=(
diff --git a/lib/galaxy/webapps/galaxy/api/genomes.py b/lib/galaxy/webapps/galaxy/api/genomes.py
index ae72b4294fe..7c40664246f 100644
--- a/lib/galaxy/webapps/galaxy/api/genomes.py
+++ b/lib/galaxy/webapps/galaxy/api/genomes.py
@@ -53,7 +53,9 @@ FormatQueryParam: str = Query(None, title="Format", description="Format")
ReferenceQueryParam: bool = Query(None, title="Reference", description="If true, return reference data")
IndexTypeQueryParam: str = Query(
- "fasta_indexes", title="Index type", description="Index type" # currently this is the only supported index type
+ "fasta_indexes",
+ title="Index type",
+ description="Index type", # currently this is the only supported index type
)
diff --git a/lib/galaxy/webapps/galaxy/api/group_roles.py b/lib/galaxy/webapps/galaxy/api/group_roles.py
index 2e2951ba3de..c7129e6b18e 100644
--- a/lib/galaxy/webapps/galaxy/api/group_roles.py
+++ b/lib/galaxy/webapps/galaxy/api/group_roles.py
@@ -3,7 +3,6 @@ API operations on Group objects.
"""
import logging
-from typing import Optional
from galaxy.managers.context import ProvidesAppContext
from galaxy.managers.group_roles import GroupRolesManager
@@ -28,7 +27,7 @@ log = logging.getLogger(__name__)
router = Router(tags=["group_roles"])
-def group_role_to_model(trans, group_id: int, role, displayed_name: Optional[str] = None) -> GroupRoleResponse:
+def group_role_to_model(trans, group_id: int, role, displayed_name: str | None = None) -> GroupRoleResponse:
encoded_group_id = Security.security.encode_id(group_id)
encoded_role_id = Security.security.encode_id(role.id)
url = trans.url_builder("group_role", group_id=encoded_group_id, role_id=encoded_role_id)
diff --git a/lib/galaxy/webapps/galaxy/api/histories.py b/lib/galaxy/webapps/galaxy/api/histories.py
index 9181b844e18..f38e16eb0c3 100644
--- a/lib/galaxy/webapps/galaxy/api/histories.py
+++ b/lib/galaxy/webapps/galaxy/api/histories.py
@@ -9,8 +9,6 @@ from typing import (
Annotated,
Any,
Literal,
- Optional,
- Union,
)
from fastapi import (
@@ -120,7 +118,7 @@ AllHistoriesQueryParam = Query(
),
)
-JehaIDPathParam: Union[DecodedDatabaseIdField, LatestLiteral] = Path(
+JehaIDPathParam: DecodedDatabaseIdField | LatestLiteral = Path(
title="Job Export History ID",
description=(
"The ID of the specific Job Export History Association or "
@@ -129,7 +127,7 @@ JehaIDPathParam: Union[DecodedDatabaseIdField, LatestLiteral] = Path(
examples=["latest"],
)
-SearchQueryParam: Optional[str] = search_query_param(
+SearchQueryParam: str | None = search_query_param(
model_name="History",
tags=query_tags,
free_text_fields=["title", "description", "slug", "tag"],
@@ -143,7 +141,7 @@ ShowSharedQueryParam: bool = Query(
default=False, title="Include histories shared with authenticated user.", description=""
)
-ShowArchivedQueryParam: Optional[bool] = Query(
+ShowArchivedQueryParam: bool | None = Query(
default=None,
title="Show Archived",
description="Whether to include archived histories.",
@@ -199,10 +197,7 @@ def _index_exports_response_discriminator(value: Any) -> str:
IndexExportsResponse = Annotated[
- Union[
- Annotated[JobExportHistoryArchiveListResponse, Tag("jobs")],
- Annotated[ExportTaskListResponse, Tag("tasks")],
- ],
+ Annotated[JobExportHistoryArchiveListResponse, Tag("jobs")] | Annotated[ExportTaskListResponse, Tag("tasks")],
Discriminator(_index_exports_response_discriminator),
]
@@ -221,19 +216,19 @@ class FastAPIHistories:
self,
response: Response,
trans: ProvidesHistoryContext = DependsOnTrans,
- limit: Optional[int] = LimitQueryParam,
- offset: Optional[int] = OffsetQueryParam,
+ limit: int | None = LimitQueryParam,
+ offset: int | None = OffsetQueryParam,
show_own: bool = ShowOwnQueryParam,
show_published: bool = ShowPublishedQueryParam,
show_shared: bool = ShowSharedQueryParam,
- show_archived: Optional[bool] = ShowArchivedQueryParam,
+ show_archived: bool | None = ShowArchivedQueryParam,
sort_by: HistorySortByEnum = SortByQueryParam,
sort_desc: bool = SortDescQueryParam,
- search: Optional[str] = SearchQueryParam,
+ search: str | None = SearchQueryParam,
filter_query_params: FilterQueryParams = Depends(get_filter_query_params),
serialization_params: SerializationParams = Depends(query_serialization_params),
- all: Optional[bool] = AllHistoriesQueryParam,
- deleted: Optional[bool] = Query( # This is for backward compatibility but looks redundant
+ all: bool | None = AllHistoriesQueryParam,
+ deleted: bool | None = Query( # This is for backward compatibility but looks redundant
default=False,
title="Deleted Only",
description="Whether to return only deleted items.",
@@ -282,7 +277,7 @@ class FastAPIHistories:
trans: ProvidesHistoryContext = DependsOnTrans,
filter_query_params: FilterQueryParams = Depends(get_filter_query_params),
serialization_params: SerializationParams = Depends(query_serialization_params),
- all: Optional[bool] = AllHistoriesQueryParam,
+ all: bool | None = AllHistoriesQueryParam,
) -> list[AnyHistoryView]:
return self.service.index(
trans, serialization_params, filter_query_params, deleted_only=True, all_histories=all
@@ -379,11 +374,11 @@ class FastAPIHistories:
default=False,
description="Include deleted datasets and collections.",
),
- seed_src: Optional[NodeSrc] = Query(
+ seed_src: NodeSrc | None = Query(
default=None,
description="Optional: src of the node to focus the subgraph on. Provide with seed_id.",
),
- seed_id: Optional[str] = Query(
+ seed_id: str | None = Query(
default=None,
description="Optional: encoded id of the node to focus the subgraph on. Provide with seed_src.",
),
@@ -397,11 +392,11 @@ class FastAPIHistories:
ge=1,
le=20,
),
- seed_scope_src: Optional[Literal["hda", "hdca"]] = Query(
+ seed_scope_src: Literal["hda", "hdca"] | None = Query(
default=None,
description="src of the item to center the selection window on. Required with seed_scope_id.",
),
- seed_scope_id: Optional[str] = Query(
+ seed_scope_id: str | None = Query(
default=None,
description="Center the selection window on this encoded id. Provide with seed_scope_src.",
),
@@ -483,9 +478,9 @@ class FastAPIHistories:
self,
trans: ProvidesHistoryContext = DependsOnTrans,
payload: CreateHistoryPayload = Depends(CreateHistoryFormData.as_form), # type: ignore[attr-defined]
- payload_as_json: Optional[Any] = Depends(try_get_request_body_as_json),
+ payload_as_json: Any | None = Depends(try_get_request_body_as_json),
serialization_params: SerializationParams = Depends(query_serialization_params),
- ) -> Union[JobImportHistoryResponse, AnyHistoryView]:
+ ) -> JobImportHistoryResponse | AnyHistoryView:
"""The new history can also be copied form a existing history or imported from an archive or URL."""
# This action needs to work both with json and x-www-form-urlencoded payloads.
# The way to support different content types on the same path operation is reading
@@ -508,7 +503,7 @@ class FastAPIHistories:
trans: ProvidesHistoryContext = DependsOnTrans,
serialization_params: SerializationParams = Depends(query_serialization_params),
purge: bool = Query(default=False),
- payload: Optional[DeleteHistoryPayload] = Body(default=None),
+ payload: DeleteHistoryPayload | None = Body(default=None),
) -> AnyHistoryView:
if payload:
purge = payload.purge
@@ -628,8 +623,8 @@ class FastAPIHistories:
self,
history_id: HistoryIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- limit: Optional[int] = LimitQueryParam,
- offset: Optional[int] = OffsetQueryParam,
+ limit: int | None = LimitQueryParam,
+ offset: int | None = OffsetQueryParam,
accept: IndexExportsAcceptHeader = "application/json",
) -> IndexExportsResponse:
"""
@@ -661,7 +656,7 @@ class FastAPIHistories:
response: Response,
history_id: HistoryIDPathParam,
trans=DependsOnTrans,
- payload: Optional[ExportHistoryArchivePayload] = Body(None),
+ payload: ExportHistoryArchivePayload | None = Body(None),
) -> HistoryArchiveExportResult:
"""This will start a job to create a history export archive.
@@ -697,7 +692,7 @@ class FastAPIHistories:
self,
history_id: HistoryIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- jeha_id: Union[DecodedDatabaseIdField, LatestLiteral] = JehaIDPathParam,
+ jeha_id: DecodedDatabaseIdField | LatestLiteral = JehaIDPathParam,
):
"""
See ``PUT /api/histories/{id}/exports`` to initiate the creation
@@ -736,7 +731,7 @@ class FastAPIHistories:
self,
history_id: HistoryIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- payload: Optional[ArchiveHistoryRequestPayload] = Body(default=None),
+ payload: ArchiveHistoryRequestPayload | None = Body(default=None),
) -> AnyArchivedHistoryView:
"""Marks the given history as 'archived' and returns the history.
@@ -764,7 +759,7 @@ class FastAPIHistories:
self,
history_id: HistoryIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- force: Optional[bool] = Query(
+ force: bool | None = Query(
default=None,
description="If true, the history will be un-archived even if it has an associated archive export record and was purged.",
),
diff --git a/lib/galaxy/webapps/galaxy/api/history_contents.py b/lib/galaxy/webapps/galaxy/api/history_contents.py
index e8173e38197..0f4d07f5255 100644
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -6,8 +6,6 @@ import logging
from typing import (
Annotated,
Literal,
- Optional,
- Union,
)
from fastapi import (
@@ -102,7 +100,7 @@ log = logging.getLogger(__name__)
router = Router(tags=["histories"])
-def ContentTypeQueryParam(default: Optional[HistoryContentType]):
+def ContentTypeQueryParam(default: HistoryContentType | None):
return Query(
default=default,
title="Content Type",
@@ -165,7 +163,7 @@ StorageRunItemsSearchTags = [
IndexQueryTag("dataset_id", "Encoded dataset id.", alias="dataset"),
]
-StorageRunSearchQueryParam: Optional[str] = search_query_param(
+StorageRunSearchQueryParam: str | None = search_query_param(
model_name="Storage operation run item",
tags=StorageRunItemsSearchTags,
free_text_fields=["state", "reason_code", "dataset_id"],
@@ -197,7 +195,7 @@ CONTENT_DELETE_RESPONSES = {
def get_index_query_params(
- v: Optional[str] = Query( # Should this be deprecated at some point and directly use the latest version by default?
+ v: str | None = Query( # Should this be deprecated at some point and directly use the latest version by default?
default=None,
title="Version",
description=(
@@ -206,7 +204,7 @@ def get_index_query_params(
),
examples=["dev"],
),
- dataset_details: Optional[str] = Query(
+ dataset_details: str | None = Query(
default=None,
alias="details",
title="Dataset Details",
@@ -226,8 +224,8 @@ def get_index_query_params(
def parse_index_query_params(
- v: Optional[str] = None,
- dataset_details: Optional[str] = None,
+ v: str | None = None,
+ dataset_details: str | None = None,
**_, # Additional params are ignored
) -> HistoryContentsIndexParams:
"""Parses query parameters for the history contents `index` operation
@@ -306,12 +304,12 @@ DryRunQueryParam = Query(
def get_legacy_index_query_params(
- ids: Optional[str] = LegacyIdsQueryParam,
- types: Optional[list[str]] = LegacyTypesQueryParam,
- details: Optional[str] = LegacyDetailsQueryParam,
- deleted: Optional[bool] = LegacyDeletedQueryParam,
- visible: Optional[bool] = LegacyVisibleQueryParam,
- shareable: Optional[bool] = LegacyShareableQueryParam,
+ ids: str | None = LegacyIdsQueryParam,
+ types: list[str] | None = LegacyTypesQueryParam,
+ details: str | None = LegacyDetailsQueryParam,
+ deleted: bool | None = LegacyDeletedQueryParam,
+ visible: bool | None = LegacyVisibleQueryParam,
+ shareable: bool | None = LegacyShareableQueryParam,
) -> LegacyHistoryContentsIndexParams:
"""This function is meant to be used as a dependency to render the OpenAPI documentation
correctly"""
@@ -326,12 +324,12 @@ def get_legacy_index_query_params(
def parse_legacy_index_query_params(
- ids: Optional[str] = None,
- types: Optional[Union[list[str], str]] = None,
- details: Optional[str] = None,
- deleted: Optional[bool] = None,
- visible: Optional[bool] = None,
- shareable: Optional[bool] = None,
+ ids: str | None = None,
+ types: list[str] | str | None = None,
+ details: str | None = None,
+ deleted: bool | None = None,
+ visible: bool | None = None,
+ shareable: bool | None = None,
**_, # Additional params are ignored
) -> LegacyHistoryContentsIndexParams:
"""Parses (legacy) query parameters for the history contents `index` operation
@@ -362,7 +360,7 @@ def parse_legacy_index_query_params(
raise validation_error_to_message_exception(e)
-def parse_content_types(types: Union[list[str], str]) -> list[HistoryContentType]:
+def parse_content_types(types: list[str] | str) -> list[HistoryContentType]:
if isinstance(types, list) and len(types) == 1: # Support ?types=dataset,dataset_collection
content_types = util.listify(types[0])
else: # Support ?types=dataset&types=dataset_collection
@@ -370,18 +368,18 @@ def parse_content_types(types: Union[list[str], str]) -> list[HistoryContentType
return [HistoryContentType[content_type] for content_type in content_types]
-def parse_dataset_details(details: Optional[str]):
+def parse_dataset_details(details: str | None):
"""Parses the different values that the `dataset_details` parameter
can have from a string."""
if details is not None and details != "all":
- dataset_details: Union[None, set[str], str] = set(util.listify(details))
+ dataset_details: None | set[str] | str = set(util.listify(details))
else: # either None or 'all'
dataset_details = details
return dataset_details
def get_index_jobs_summary_params(
- ids: Optional[str] = Query(
+ ids: str | None = Query(
default=None,
title="IDs",
description=(
@@ -389,7 +387,7 @@ def get_index_jobs_summary_params(
"is specified types must also be specified and have same length."
),
),
- types: Optional[str] = Query(
+ types: str | None = Query(
default=None,
title="Types",
description=(
@@ -407,8 +405,8 @@ def get_index_jobs_summary_params(
def parse_index_jobs_summary_params(
- ids: Optional[str] = None,
- types: Optional[str] = None,
+ ids: str | None = None,
+ types: str | None = None,
**_, # Additional params are ignored
) -> HistoryContentsIndexJobsSummaryParams:
"""Parses query parameters for the history contents `index_jobs_summary` operation
@@ -463,7 +461,7 @@ class FastAPIHistoryContents:
serialization_params: SerializationParams = Depends(query_serialization_params),
filter_query_params: FilterQueryParams = Depends(get_filter_query_params),
accept: HistoryIndexAcceptContentTypes = "application/json",
- ) -> Union[HistoryContentsResult, HistoryContentsWithStatsResult]:
+ ) -> HistoryContentsResult | HistoryContentsWithStatsResult:
"""
Return a list of either `HDA`/`HDCA` data for the history with the given ``ID``.
@@ -497,12 +495,12 @@ class FastAPIHistoryContents:
history_id: HistoryIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
index_params: HistoryContentsIndexParams = Depends(get_index_query_params),
- type: Optional[str] = Query(default=None, include_in_schema=False, deprecated=True),
+ type: str | None = Query(default=None, include_in_schema=False, deprecated=True),
legacy_params: LegacyHistoryContentsIndexParams = Depends(get_legacy_index_query_params),
serialization_params: SerializationParams = Depends(query_serialization_params),
filter_query_params: FilterQueryParams = Depends(get_filter_query_params),
accept: HistoryIndexAcceptContentTypes = "application/json",
- ) -> Union[HistoryContentsResult, HistoryContentsWithStatsResult]:
+ ) -> HistoryContentsResult | HistoryContentsWithStatsResult:
"""
Return a list of `HDA`/`HDCA` data for the history with the given ``ID``.
@@ -557,7 +555,7 @@ class FastAPIHistoryContents:
history_id: HistoryIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
type: HistoryContentType = ContentTypePathParam,
- fuzzy_count: Optional[int] = FuzzyCountQueryParam,
+ fuzzy_count: int | None = FuzzyCountQueryParam,
serialization_params: SerializationParams = Depends(query_serialization_params),
) -> AnyHistoryContentItem:
"""
@@ -587,7 +585,7 @@ class FastAPIHistoryContents:
history_id: HistoryIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
type: HistoryContentType = ContentTypeQueryParam(default=HistoryContentType.dataset),
- fuzzy_count: Optional[int] = FuzzyCountQueryParam,
+ fuzzy_count: int | None = FuzzyCountQueryParam,
serialization_params: SerializationParams = Depends(query_serialization_params),
) -> AnyHistoryContentItem:
"""
@@ -687,7 +685,7 @@ class FastAPIHistoryContents:
self,
hdca_id: HistoryHDCAIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- history_id: Optional[DecodedDatabaseIdField] = Path(
+ history_id: DecodedDatabaseIdField | None = Path(
description="The encoded database identifier of the History.",
),
):
@@ -753,7 +751,7 @@ class FastAPIHistoryContents:
type: HistoryContentType = ContentTypePathParam,
serialization_params: SerializationParams = Depends(query_serialization_params),
payload: CreateHistoryContentPayload = Body(...),
- ) -> Union[AnyHistoryContentItem, list[AnyHistoryContentItem]]:
+ ) -> AnyHistoryContentItem | list[AnyHistoryContentItem]:
"""Create a new `HDA` or `HDCA` in the given History."""
return self._create(trans, history_id, type, serialization_params, payload)
@@ -768,10 +766,10 @@ class FastAPIHistoryContents:
self,
history_id: HistoryIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- type: Optional[HistoryContentType] = ContentTypeQueryParam(default=None),
+ type: HistoryContentType | None = ContentTypeQueryParam(default=None),
serialization_params: SerializationParams = Depends(query_serialization_params),
payload: CreateHistoryContentPayload = Body(...),
- ) -> Union[AnyHistoryContentItem, list[AnyHistoryContentItem]]:
+ ) -> AnyHistoryContentItem | list[AnyHistoryContentItem]:
"""Create a new `HDA` or `HDCA` in the given History."""
return self._create(trans, history_id, type, serialization_params, payload)
@@ -779,10 +777,10 @@ class FastAPIHistoryContents:
self,
trans: ProvidesHistoryContext,
history_id: DecodedDatabaseIdField,
- type: Optional[HistoryContentType],
+ type: HistoryContentType | None,
serialization_params: SerializationParams,
payload: CreateHistoryContentPayload,
- ) -> Union[AnyHistoryContentItem, list[AnyHistoryContentItem]]:
+ ) -> AnyHistoryContentItem | list[AnyHistoryContentItem]:
"""Create a new `HDA` or `HDCA` in the given History."""
payload.type = type or payload.type
return self.service.create(trans, history_id, payload, serialization_params)
@@ -888,7 +886,7 @@ class FastAPIHistoryContents:
trans: ProvidesHistoryContext = DependsOnTrans,
offset: int = StorageRunOffsetQueryParam,
limit: int = StorageRunLimitQueryParam,
- search: Optional[str] = StorageRunSearchQueryParam,
+ search: str | None = StorageRunSearchQueryParam,
) -> list[StorageOperationRunItemStatus]:
run_items, total_matches = self.service.bulk_storage_operation_run_items(
trans,
@@ -1012,9 +1010,9 @@ class FastAPIHistoryContents:
id: HistoryItemIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
type: HistoryContentType = ContentTypePathParam,
- purge: Optional[bool] = PurgeQueryParam,
- recursive: Optional[bool] = RecursiveQueryParam,
- stop_job: Optional[bool] = StopJobQueryParam,
+ purge: bool | None = PurgeQueryParam,
+ recursive: bool | None = RecursiveQueryParam,
+ stop_job: bool | None = StopJobQueryParam,
payload: DeleteHistoryContentPayload = Body(None),
):
"""
@@ -1046,9 +1044,9 @@ class FastAPIHistoryContents:
id: HistoryItemIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
type: HistoryContentType = ContentTypeQueryParam(default=HistoryContentType.dataset),
- purge: Optional[bool] = PurgeQueryParam,
- recursive: Optional[bool] = RecursiveQueryParam,
- stop_job: Optional[bool] = StopJobQueryParam,
+ purge: bool | None = PurgeQueryParam,
+ recursive: bool | None = RecursiveQueryParam,
+ stop_job: bool | None = StopJobQueryParam,
payload: DeleteHistoryContentPayload = Body(None),
):
"""
@@ -1078,9 +1076,9 @@ class FastAPIHistoryContents:
response: Response,
dataset_id: HistoryItemIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- purge: Optional[bool] = PurgeQueryParam,
- recursive: Optional[bool] = RecursiveQueryParam,
- stop_job: Optional[bool] = StopJobQueryParam,
+ purge: bool | None = PurgeQueryParam,
+ recursive: bool | None = RecursiveQueryParam,
+ stop_job: bool | None = StopJobQueryParam,
payload: DeleteHistoryContentPayload = Body(None),
):
"""
@@ -1105,9 +1103,9 @@ class FastAPIHistoryContents:
trans: ProvidesHistoryContext,
id: DecodedDatabaseIdField,
type: HistoryContentType,
- purge: Optional[bool],
- recursive: Optional[bool],
- stop_job: Optional[bool],
+ purge: bool | None,
+ recursive: bool | None,
+ stop_job: bool | None,
payload: DeleteHistoryContentPayload,
):
# TODO: should we just use the default payload and deprecate the query params?
@@ -1140,7 +1138,7 @@ class FastAPIHistoryContents:
description="Output format of the archive.",
deprecated=True, # Looks like is not really used?
),
- dry_run: Optional[bool] = DryRunQueryParam,
+ dry_run: bool | None = DryRunQueryParam,
filter_query_params: FilterQueryParams = Depends(get_filter_query_params),
):
"""Build and return a compressed archive of the selected history contents."""
@@ -1159,8 +1157,8 @@ class FastAPIHistoryContents:
self,
history_id: HistoryIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- filename: Optional[str] = ArchiveFilenameQueryParam,
- dry_run: Optional[bool] = DryRunQueryParam,
+ filename: str | None = ArchiveFilenameQueryParam,
+ dry_run: bool | None = DryRunQueryParam,
filter_query_params: FilterQueryParams = Depends(get_filter_query_params),
):
"""Build and return a compressed archive of the selected history contents."""
diff --git a/lib/galaxy/webapps/galaxy/api/job_files.py b/lib/galaxy/webapps/galaxy/api/job_files.py
index a125a05a59b..805767488fb 100644
--- a/lib/galaxy/webapps/galaxy/api/job_files.py
+++ b/lib/galaxy/webapps/galaxy/api/job_files.py
@@ -6,7 +6,6 @@ import logging
import os
import re
import shutil
-from typing import Union
from galaxy import (
exceptions,
@@ -230,7 +229,7 @@ class JobFilesAPIController(BaseGalaxyAPIController):
"""Check if is an output path for this job or a file in the an
output's extra files path.
"""
- all_output_assocs: list[Union[JobToOutputDatasetAssociation, JobToOutputLibraryDatasetAssociation]] = [
+ all_output_assocs: list[JobToOutputDatasetAssociation | JobToOutputLibraryDatasetAssociation] = [
*job.output_datasets,
*job.output_library_datasets,
]
diff --git a/lib/galaxy/webapps/galaxy/api/jobs.py b/lib/galaxy/webapps/galaxy/api/jobs.py
index 73bc40c1e5b..322abe20c3a 100644
--- a/lib/galaxy/webapps/galaxy/api/jobs.py
+++ b/lib/galaxy/webapps/galaxy/api/jobs.py
@@ -12,8 +12,6 @@ from datetime import (
from typing import (
Annotated,
Any,
- Optional,
- Union,
)
from fastapi import (
@@ -99,7 +97,7 @@ UserDetailsQueryParam: bool = Query(
description="If true, and requester is an admin, will return external job id and user email. This is only available to admins.",
)
-UserIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+UserIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None,
title="User ID",
description="an encoded user id to restrict query to, must be own id if not admin user",
@@ -127,43 +125,43 @@ ToolIdLikeQueryParam = Query(
description="Limit listing of jobs to those that match one of the included tool ID sql-like patterns. If none, all are returned",
)
-DateRangeMinQueryParam: Optional[Union[OffsetNaiveDatetime, date]] = Query(
+DateRangeMinQueryParam: OffsetNaiveDatetime | date | None = Query(
default=None,
title="Date Range Minimum",
description="Limit listing of jobs to those that are updated after specified date (e.g. '2014-01-01')",
)
-DateRangeMaxQueryParam: Optional[Union[OffsetNaiveDatetime, date]] = Query(
+DateRangeMaxQueryParam: OffsetNaiveDatetime | date | None = Query(
default=None,
title="Date Range Maximum",
description="Limit listing of jobs to those that are updated before specified date (e.g. '2014-01-01')",
)
-HistoryIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+HistoryIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None,
title="History ID",
description="Limit listing of jobs to those that match the history_id. If none, jobs from any history may be returned.",
)
-WorkflowIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+WorkflowIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None,
title="Workflow ID",
description="Limit listing of jobs to those that match the specified workflow ID. If none, jobs from any workflow (or from no workflows) may be returned.",
)
-InvocationIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+InvocationIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None,
title="Invocation ID",
description="Limit listing of jobs to those that match the specified workflow invocation ID. If none, jobs from any workflow invocation (or from no workflows) may be returned.",
)
-ImplicitCollectionJobsIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+ImplicitCollectionJobsIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None,
title="Implicit Collection Jobs ID",
description="Limit listing of jobs to those that match the specified implicit collection job ID. If none, jobs from any implicit collection execution (or from no implicit collection execution) may be returned.",
)
-ToolRequestIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+ToolRequestIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None,
title="Tool Request ID",
description="Limit listing of jobs to those that were created from the supplied tool request ID. If none, jobs from any tool request (or from no workflows) may be returned.",
@@ -191,14 +189,14 @@ query_tags = [
IndexQueryTag("handler", "The job handler name used to execute the job.", "h", admin_only=True),
]
-SearchQueryParam: Optional[str] = search_query_param(
+SearchQueryParam: str | None = search_query_param(
model_name="Job",
tags=query_tags,
free_text_fields=["user", "tool", "handler", "runner"],
)
-FullShowQueryParam: Optional[bool] = Query(title="Full show", description="Show extra information.")
-DeprecatedHdaLddaQueryParam: Optional[DatasetSourceType] = Query(
+FullShowQueryParam: bool | None = Query(title="Full show", description="Show extra information.")
+DeprecatedHdaLddaQueryParam: DatasetSourceType | None = Query(
deprecated=True,
title="HDA or LDDA",
description="Whether this dataset belongs to a history (HDA) or a library (LDDA).",
@@ -218,47 +216,47 @@ DeleteJobBody = Body(title="Delete/cancel job", description="The values to delet
class ShowFullJobResponse(EncodedJobDetails):
- tool_stdout: Optional[str] = Field(
+ tool_stdout: str | None = Field(
default=None,
title="Tool Standard Output",
description="The captured standard output of the tool executed by the job.",
)
- tool_stderr: Optional[str] = Field(
+ tool_stderr: str | None = Field(
default=None,
title="Tool Standard Error",
description="The captured standard error of the tool executed by the job.",
)
- job_stdout: Optional[str] = Field(
+ job_stdout: str | None = Field(
default=None,
title="Job Standard Output",
description="The captured standard output of the job execution.",
)
- job_stderr: Optional[str] = Field(
+ job_stderr: str | None = Field(
default=None,
title="Job Standard Error",
description="The captured standard error of the job execution.",
)
- stdout: Optional[str] = Field( # Legacy (tool_stdout + "\n" + job_stdout)
+ stdout: str | None = Field( # Legacy (tool_stdout + "\n" + job_stdout)
default=None,
title="Standard Output",
description="Combined tool and job standard output streams.",
)
- stderr: Optional[str] = Field( # Legacy (tool_stderr + "\n" + job_stderr)
+ stderr: str | None = Field( # Legacy (tool_stderr + "\n" + job_stderr)
default=None,
title="Standard Error",
description="Combined tool and job standard error streams.",
)
- job_messages: Optional[list[AnyJobMessage]] = Field(
+ job_messages: list[AnyJobMessage] | None = Field(
default=None,
title="Job Messages",
description="List with additional information and possible reasons for a failed job.",
)
- dependencies: Optional[list[Any]] = Field(
+ dependencies: list[Any] | None = Field(
default=None,
title="Job dependencies",
description="The dependencies of the job.",
)
- job_metrics: Optional[JobMetricCollection] = Field(
+ job_metrics: JobMetricCollection | None = Field(
default=None,
title="Job Metrics",
description=(
@@ -283,24 +281,24 @@ class FastAPIJobs:
def index(
self,
trans: ProvidesUserContext = DependsOnTrans,
- states: Optional[list[str]] = Depends(query_parameter_as_list(StateQueryParam)),
+ states: list[str] | None = Depends(query_parameter_as_list(StateQueryParam)),
user_details: bool = UserDetailsQueryParam,
- user_id: Optional[DecodedDatabaseIdField] = UserIdQueryParam,
+ user_id: DecodedDatabaseIdField | None = UserIdQueryParam,
view: JobIndexViewEnum = ViewQueryParam,
- tool_ids: Optional[list[str]] = Depends(query_parameter_as_list(ToolIdQueryParam)),
- tool_ids_like: Optional[list[str]] = Depends(query_parameter_as_list(ToolIdLikeQueryParam)),
- date_range_min: Optional[Union[datetime, date]] = DateRangeMinQueryParam,
- date_range_max: Optional[Union[datetime, date]] = DateRangeMaxQueryParam,
- history_id: Optional[DecodedDatabaseIdField] = HistoryIdQueryParam,
- workflow_id: Optional[DecodedDatabaseIdField] = WorkflowIdQueryParam,
- invocation_id: Optional[DecodedDatabaseIdField] = InvocationIdQueryParam,
- implicit_collection_jobs_id: Optional[DecodedDatabaseIdField] = ImplicitCollectionJobsIdQueryParam,
- tool_request_id: Optional[DecodedDatabaseIdField] = ToolRequestIdQueryParam,
+ tool_ids: list[str] | None = Depends(query_parameter_as_list(ToolIdQueryParam)),
+ tool_ids_like: list[str] | None = Depends(query_parameter_as_list(ToolIdLikeQueryParam)),
+ date_range_min: datetime | date | None = DateRangeMinQueryParam,
+ date_range_max: datetime | date | None = DateRangeMaxQueryParam,
+ history_id: DecodedDatabaseIdField | None = HistoryIdQueryParam,
+ workflow_id: DecodedDatabaseIdField | None = WorkflowIdQueryParam,
+ invocation_id: DecodedDatabaseIdField | None = InvocationIdQueryParam,
+ implicit_collection_jobs_id: DecodedDatabaseIdField | None = ImplicitCollectionJobsIdQueryParam,
+ tool_request_id: DecodedDatabaseIdField | None = ToolRequestIdQueryParam,
order_by: JobIndexSortByEnum = SortByQueryParam,
- search: Optional[str] = SearchQueryParam,
+ search: str | None = SearchQueryParam,
limit: int = LimitQueryParam,
offset: int = OffsetQueryParam,
- ) -> list[Union[ShowFullJobResponse, EncodedJobDetails, JobSummary]]:
+ ) -> list[ShowFullJobResponse | EncodedJobDetails | JobSummary]:
payload = JobIndexPayload.model_construct(
states=states,
user_details=user_details,
@@ -435,10 +433,10 @@ class FastAPIJobs:
self,
job_id: JobIdPathParam,
trans: ProvidesUserContext = DependsOnTrans,
- ) -> list[Union[JobOutputAssociation, JobOutputCollectionAssociation]]:
+ ) -> list[JobOutputAssociation | JobOutputCollectionAssociation]:
job = self.service.get_job(trans=trans, job_id=job_id)
associations = self.service.dictify_associations(trans, job.output_datasets, job.output_library_datasets)
- output_associations: list[Union[JobOutputAssociation, JobOutputCollectionAssociation]] = []
+ output_associations: list[JobOutputAssociation | JobOutputCollectionAssociation] = []
for association in associations:
output_associations.append(JobOutputAssociation(name=association.name, dataset=association.dataset))
@@ -484,7 +482,7 @@ class FastAPIJobs:
def parameters_display_by_job(
self,
job_id: JobIdPathParam,
- hda_ldda: Annotated[Optional[DatasetSourceType], DeprecatedHdaLddaQueryParam] = DatasetSourceType.hda,
+ hda_ldda: Annotated[DatasetSourceType | None, DeprecatedHdaLddaQueryParam] = DatasetSourceType.hda,
trans: ProvidesUserContext = DependsOnTrans,
) -> JobDisplayParametersSummary:
"""Resolve parameters as a list for nested display."""
@@ -517,9 +515,9 @@ class FastAPIJobs:
def metrics_by_job(
self,
job_id: JobIdPathParam,
- hda_ldda: Annotated[Optional[DatasetSourceType], DeprecatedHdaLddaQueryParam] = DatasetSourceType.hda,
+ hda_ldda: Annotated[DatasetSourceType | None, DeprecatedHdaLddaQueryParam] = DatasetSourceType.hda,
trans: ProvidesUserContext = DependsOnTrans,
- ) -> list[Optional[JobMetric]]:
+ ) -> list[JobMetric | None]:
hda_ldda_str = hda_ldda or "hda"
job = self.service.get_job(trans, job_id=job_id, hda_ldda=hda_ldda_str)
return [JobMetric(**metric) for metric in summarize_job_metrics(trans, job)]
@@ -535,7 +533,7 @@ class FastAPIJobs:
dataset_id: DatasetIdPathParam,
hda_ldda: Annotated[DatasetSourceType, HdaLddaQueryParam] = DatasetSourceType.hda,
trans: ProvidesUserContext = DependsOnTrans,
- ) -> list[Optional[JobMetric]]:
+ ) -> list[JobMetric | None]:
job = self.service.get_job(trans, dataset_id=dataset_id, hda_ldda=hda_ldda)
return [JobMetric(**metric) for metric in summarize_job_metrics(trans, job)]
@@ -607,9 +605,9 @@ class FastAPIJobs:
def show(
self,
job_id: JobIdPathParam,
- full: Annotated[Optional[bool], FullShowQueryParam] = False,
+ full: Annotated[bool | None, FullShowQueryParam] = False,
trans: ProvidesUserContext = DependsOnTrans,
- ) -> Union[ShowFullJobResponse, EncodedJobDetails]:
+ ) -> ShowFullJobResponse | EncodedJobDetails:
if full:
return ShowFullJobResponse(**self.service.show(trans, job_id, bool(full)))
else:
@@ -654,7 +652,7 @@ class FastAPIJobs:
self,
job_id: JobIdPathParam,
trans: ProvidesUserContext = DependsOnTrans,
- payload: Annotated[Optional[DeleteJobPayload], DeleteJobBody] = None,
+ payload: Annotated[DeleteJobPayload | None, DeleteJobBody] = None,
) -> bool:
job = self.service.get_job(trans=trans, job_id=job_id)
if payload:
diff --git a/lib/galaxy/webapps/galaxy/api/libraries.py b/lib/galaxy/webapps/galaxy/api/libraries.py
index 4436bca293d..96fcf0ecb30 100644
--- a/lib/galaxy/webapps/galaxy/api/libraries.py
+++ b/lib/galaxy/webapps/galaxy/api/libraries.py
@@ -3,10 +3,6 @@ API operations on a data library.
"""
import logging
-from typing import (
- Optional,
- Union,
-)
from fastapi import (
Body,
@@ -41,11 +37,11 @@ log = logging.getLogger(__name__)
router = Router(tags=["libraries"])
-DeletedQueryParam: Optional[bool] = Query(
+DeletedQueryParam: bool | None = Query(
default=None, title="Display deleted", description="Whether to include deleted libraries in the result."
)
-UndeleteQueryParam: Optional[bool] = Query(
+UndeleteQueryParam: bool | None = Query(
default=None, title="Undelete", description="Whether to restore a deleted library."
)
@@ -61,7 +57,7 @@ class FastAPILibraries:
def index(
self,
trans: ProvidesUserContext = DependsOnTrans,
- deleted: Optional[bool] = DeletedQueryParam,
+ deleted: bool | None = DeletedQueryParam,
) -> LibrarySummaryList:
"""Returns a list of summary data for all libraries."""
return self.service.index(trans, deleted)
@@ -138,8 +134,8 @@ class FastAPILibraries:
self,
id: LibraryIdPathParam,
trans: ProvidesUserContext = DependsOnTrans,
- undelete: Optional[bool] = UndeleteQueryParam,
- payload: Optional[DeleteLibraryPayload] = Body(default=None),
+ undelete: bool | None = UndeleteQueryParam,
+ payload: DeleteLibraryPayload | None = Body(default=None),
) -> LibrarySummary:
"""Marks the specified library as deleted (or undeleted).
Currently, only admin users can delete or restore libraries."""
@@ -155,12 +151,12 @@ class FastAPILibraries:
self,
id: LibraryIdPathParam,
trans: ProvidesUserContext = DependsOnTrans,
- scope: Optional[LibraryPermissionScope] = Query(
+ scope: LibraryPermissionScope | None = Query(
None,
title="Scope",
description="The scope of the permissions to retrieve. Either the `current` permissions or the `available`.",
),
- is_library_access: Optional[bool] = Query(
+ is_library_access: bool | None = Query(
None,
title="Is Library Access",
description="Indicates whether the roles available for the library access are requested.",
@@ -171,10 +167,10 @@ class FastAPILibraries:
page_limit: int = Query(
default=10, title="Page Limit", description="The maximum number of permissions per page when paginating."
),
- q: Optional[str] = Query(
+ q: str | None = Query(
None, title="Query", description="Optional search text to retrieve only the roles matching this query."
),
- ) -> Union[LibraryCurrentPermissions, LibraryAvailablePermissions]:
+ ) -> LibraryCurrentPermissions | LibraryAvailablePermissions:
"""Gets the current or available permissions of a particular library.
The results can be paginated and additionally filtered by a query."""
return self.service.get_permissions(
@@ -195,16 +191,13 @@ class FastAPILibraries:
self,
id: LibraryIdPathParam,
trans: ProvidesUserContext = DependsOnTrans,
- action: Optional[LibraryPermissionAction] = Query(
+ action: LibraryPermissionAction | None = Query(
default=None,
title="Action",
description="Indicates what action should be performed on the Library.",
),
- payload: Union[
- LibraryPermissionsPayload,
- LegacyLibraryPermissionsPayload,
- ] = Body(...),
- ) -> Union[LibraryLegacySummary, LibraryCurrentPermissions]: # Old legacy response
+ payload: LibraryPermissionsPayload | LegacyLibraryPermissionsPayload = Body(...),
+ ) -> LibraryLegacySummary | LibraryCurrentPermissions: # Old legacy response
"""Sets the permissions to access and manipulate a library."""
payload_dict = payload.model_dump(by_alias=True)
if isinstance(payload, LibraryPermissionsPayload) and action is not None:
diff --git a/lib/galaxy/webapps/galaxy/api/library_contents.py b/lib/galaxy/webapps/galaxy/api/library_contents.py
index b9a512816d5..94dbe00ad46 100644
--- a/lib/galaxy/webapps/galaxy/api/library_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/library_contents.py
@@ -5,7 +5,6 @@ API operations on the contents of a data library.
import logging
from typing import (
cast,
- Optional,
)
from fastapi import (
@@ -63,7 +62,7 @@ class JsonApiRoute(APIContentTypeRoute):
LibraryContentsCreateForm = as_form(LibraryContentsFileCreatePayload)
-async def get_files(request: Request, files: Optional[list[UploadFile]] = None):
+async def get_files(request: Request, files: list[UploadFile] | None = None):
# FastAPI's UploadFile is a very light wrapper around starlette's UploadFile
files2: list[StarletteUploadFile] = cast(list[StarletteUploadFile], files or [])
if not files2:
@@ -161,7 +160,7 @@ class FastAPILibraryContents:
self,
library_id: LibraryIdPathParam,
id: LibraryDatasetIdPathParam,
- payload: Optional[LibraryContentsDeletePayload] = Body(None),
+ payload: LibraryContentsDeletePayload | None = Body(None),
trans: ProvidesHistoryContext = DependsOnTrans,
) -> LibraryContentsDeleteResponse:
"""This endpoint is deprecated. Please use DELETE /api/libraries/datasets/{id} instead."""
diff --git a/lib/galaxy/webapps/galaxy/api/mcp.py b/lib/galaxy/webapps/galaxy/api/mcp.py
index f37cb332877..104fc2a464a 100644
--- a/lib/galaxy/webapps/galaxy/api/mcp.py
+++ b/lib/galaxy/webapps/galaxy/api/mcp.py
@@ -9,7 +9,6 @@ import logging
from contextlib import contextmanager
from typing import (
Any,
- Optional,
)
from urllib.parse import urlparse
@@ -42,8 +41,7 @@ def get_mcp_url_builder(fallback_base_url: str):
from galaxy.webapps.galaxy.api import UrlBuilder
- request = _current_http_request.get(None)
- if request is not None:
+ if (request := _current_http_request.get(None)) is not None:
return UrlBuilder(request)
class MCPUrlBuilder:
@@ -110,7 +108,7 @@ class _StaticRequest(GalaxyAbstractRequest):
def is_secure(self) -> bool:
return self._parsed.scheme == "https"
- def get_cookie(self, name: str) -> Optional[str]:
+ def get_cookie(self, name: str) -> str | None:
return None
@property
@@ -132,13 +130,13 @@ class _StaticResponse(GalaxyAbstractResponse):
self,
key: str,
value: str = "",
- max_age: Optional[int] = None,
- expires: Optional[int] = None,
+ max_age: int | None = None,
+ expires: int | None = None,
path: str = "/",
- domain: Optional[str] = None,
+ domain: str | None = None,
secure: bool = False,
httponly: bool = False,
- samesite: Optional[str] = "lax",
+ samesite: str | None = "lax",
) -> None:
return None
diff --git a/lib/galaxy/webapps/galaxy/api/notifications.py b/lib/galaxy/webapps/galaxy/api/notifications.py
index f1bfbcab88a..d0789bd7e46 100644
--- a/lib/galaxy/webapps/galaxy/api/notifications.py
+++ b/lib/galaxy/webapps/galaxy/api/notifications.py
@@ -3,10 +3,6 @@ API operations on Notification objects.
"""
import logging
-from typing import (
- Optional,
- Union,
-)
from fastapi import (
Body,
@@ -108,8 +104,8 @@ class FastAPINotifications:
def get_user_notifications(
self,
trans: ProvidesUserContext = DependsOnTrans,
- limit: Optional[int] = 20,
- offset: Optional[int] = None,
+ limit: int | None = 20,
+ offset: int | None = None,
) -> UserNotificationListResponse:
"""Anonymous users cannot receive personal notifications, only broadcasted notifications.
@@ -234,7 +230,7 @@ class FastAPINotifications:
self,
trans: ProvidesUserContext = DependsOnTrans,
payload: NotificationCreateRequestBody = Body(),
- ) -> Union[NotificationCreatedResponse, AsyncTaskResultSummary]:
+ ) -> NotificationCreatedResponse | AsyncTaskResultSummary:
"""Sends a notification to a list of recipients (users, groups or roles)."""
return self.service.send_notification(sender_context=trans, payload=payload)
diff --git a/lib/galaxy/webapps/galaxy/api/oauth2_callback.py b/lib/galaxy/webapps/galaxy/api/oauth2_callback.py
index 581571c2848..1b208c1a8fb 100644
--- a/lib/galaxy/webapps/galaxy/api/oauth2_callback.py
+++ b/lib/galaxy/webapps/galaxy/api/oauth2_callback.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from fastapi import Query
from fastapi.responses import RedirectResponse
@@ -18,11 +16,11 @@ StateQueryParam: str = Query(
title="State information sent with auth request",
description="Base-64 encoded JSON used to route request within Galaxy.",
)
-CodeQueryParam: Optional[str] = Query(
+CodeQueryParam: str | None = Query(
None,
title="OAuth2 Authorization Code from remote resource",
)
-ErrorQueryParam: Optional[str] = Query(
+ErrorQueryParam: str | None = Query(
None,
title="OAuth2 Error from remote resource",
)
@@ -54,8 +52,8 @@ class OAuth2Callback:
self,
trans: SessionRequestContext = DependsOnTrans,
state: str = StateQueryParam,
- code: Optional[str] = CodeQueryParam,
- error: Optional[str] = ErrorQueryParam,
+ code: str | None = CodeQueryParam,
+ error: str | None = ErrorQueryParam,
):
if error:
error_code = self._ensure_valid_oauth_error_code(error)
diff --git a/lib/galaxy/webapps/galaxy/api/object_store.py b/lib/galaxy/webapps/galaxy/api/object_store.py
index 75fc536f8da..189fcd3c59e 100644
--- a/lib/galaxy/webapps/galaxy/api/object_store.py
+++ b/lib/galaxy/webapps/galaxy/api/object_store.py
@@ -3,9 +3,6 @@ API operations on Galaxy's object store.
"""
import logging
-from typing import (
- Union,
-)
from fastapi import (
Body,
@@ -77,7 +74,7 @@ class FastAPIObjectStore:
self,
trans: ProvidesUserContext = DependsOnTrans,
selectable: bool = SelectableQueryParam,
- ) -> list[Union[ConcreteObjectStoreModel, UserConcreteObjectStoreModel]]:
+ ) -> list[ConcreteObjectStoreModel | UserConcreteObjectStoreModel]:
if not selectable:
raise RequestParameterInvalidException(
"The object store index query currently needs to be called with selectable=true"
diff --git a/lib/galaxy/webapps/galaxy/api/pages.py b/lib/galaxy/webapps/galaxy/api/pages.py
index ff2d17479c5..d01c86bfc08 100644
--- a/lib/galaxy/webapps/galaxy/api/pages.py
+++ b/lib/galaxy/webapps/galaxy/api/pages.py
@@ -4,7 +4,6 @@ API for updating Galaxy Pages
import io
import logging
-from typing import Optional
from fastapi import (
Body,
@@ -50,7 +49,7 @@ DeletedQueryParam: bool = Query(
default=False, title="Display deleted", description="Whether to include deleted pages in the result."
)
-UserIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+UserIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None,
title="Encoded user ID to restrict query to, must be own id if not an admin user",
)
@@ -83,11 +82,11 @@ OffsetQueryParam: int = Query(
title="Number of pages to skip in sorted query (to enable pagination).",
)
-InvocationIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+InvocationIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None, title="Invocation ID", description="Filter pages by this workflow invocation ID."
)
-HistoryIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+HistoryIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None,
title="Filter pages by history ID.",
)
@@ -102,7 +101,7 @@ query_tags = [
IndexQueryTag("type", "Page type filter: 'standalone', 'history_attached', or 'all'."),
]
-SearchQueryParam: Optional[str] = search_query_param(
+SearchQueryParam: str | None = search_query_param(
model_name="Page",
tags=query_tags,
free_text_fields=["title", "slug", "tag", "user"],
@@ -125,15 +124,15 @@ class FastAPIPages:
deleted: bool = DeletedQueryParam,
limit: int = LimitQueryParam,
offset: int = OffsetQueryParam,
- search: Optional[str] = SearchQueryParam,
+ search: str | None = SearchQueryParam,
show_own: bool = ShowOwnQueryParam,
show_published: bool = ShowPublishedQueryParam,
show_shared: bool = ShowSharedQueryParam,
sort_by: PageSortByEnum = SortByQueryParam,
sort_desc: bool = SortDescQueryParam,
- user_id: Optional[DecodedDatabaseIdField] = UserIdQueryParam,
- invocation_id: Optional[DecodedDatabaseIdField] = InvocationIdQueryParam,
- history_id: Optional[DecodedDatabaseIdField] = HistoryIdQueryParam,
+ user_id: DecodedDatabaseIdField | None = UserIdQueryParam,
+ invocation_id: DecodedDatabaseIdField | None = InvocationIdQueryParam,
+ history_id: DecodedDatabaseIdField | None = HistoryIdQueryParam,
) -> PageSummaryList:
"""Get a list with summary information of all Pages available to the user."""
payload = PageIndexQueryPayload.model_construct(
diff --git a/lib/galaxy/webapps/galaxy/api/plugins.py b/lib/galaxy/webapps/galaxy/api/plugins.py
index 788b4ccdb7a..0712def24b3 100644
--- a/lib/galaxy/webapps/galaxy/api/plugins.py
+++ b/lib/galaxy/webapps/galaxy/api/plugins.py
@@ -8,8 +8,6 @@ from typing import (
Any,
cast,
Literal,
- Optional,
- Union,
)
from fastapi import (
@@ -82,8 +80,8 @@ TOP_P = 0.9
class ChatMessage(BaseModel):
role: Literal["assistant", "system", "tool", "user"]
- content: Optional[str] = None
- tool_calls: Optional[list[dict[str, Any]]] = None
+ content: str | None = None
+ tool_calls: list[dict[str, Any]] | None = None
model_config = dict(extra="allow")
@@ -100,9 +98,9 @@ class ChatTool(BaseModel):
class ChatCompletionRequest(BaseModel):
messages: list[ChatMessage]
- tools: Optional[list[ChatTool]] = None
- stream: Optional[bool] = False
- max_tokens: Optional[int] = None
+ tools: list[ChatTool] | None = None
+ stream: bool | None = False
+ max_tokens: int | None = None
model_config = dict(extra="allow")
@@ -155,7 +153,7 @@ class FastAPIPlugins:
else:
return self._create_error("Visualization registry is not available.")
- def _get_plugin_config(self, plugin_name: str, key: str) -> Optional[str]:
+ def _get_plugin_config(self, plugin_name: str, key: str) -> str | None:
"""Get config for a plugin with fallback through inference_services.
Precedence:
@@ -321,12 +319,12 @@ class FastAPIPlugins:
def index(
self,
trans: SessionRequestContext = DependsOnTrans,
- dataset_id: Optional[DecodedDatabaseIdField] = Query(
+ dataset_id: DecodedDatabaseIdField | None = Query(
default=None,
title="Dataset ID",
description="Filter to visualizations compatible with this dataset.",
),
- embeddable: Optional[bool] = Query(
+ embeddable: bool | None = Query(
default=None,
title="Embeddable",
description="Filter to embeddable visualizations only.",
@@ -348,12 +346,12 @@ class FastAPIPlugins:
title="Plugin ID",
description="The visualization plugin identifier.",
),
- history_id: Optional[DecodedDatabaseIdField] = Query(
+ history_id: DecodedDatabaseIdField | None = Query(
default=None,
title="History ID",
description="Filter datasets compatible with this plugin from the specified history.",
),
- ) -> Union[PluginDatasetsResponse, VisualizationPluginResponse]:
+ ) -> PluginDatasetsResponse | VisualizationPluginResponse:
"""Get details of a specific visualization plugin."""
registry = self._get_registry()
if history_id is not None:
diff --git a/lib/galaxy/webapps/galaxy/api/proxy.py b/lib/galaxy/webapps/galaxy/api/proxy.py
index 5d175dc03f1..1bf9652f2f2 100644
--- a/lib/galaxy/webapps/galaxy/api/proxy.py
+++ b/lib/galaxy/webapps/galaxy/api/proxy.py
@@ -66,7 +66,6 @@ def is_valid_url(url: str) -> bool:
@router.cbv
class FastAPIProxy:
-
@router.get("/api/proxy")
@router.head("/api/proxy")
async def proxy(self, request: Request, url: str = URLQueryParam, trans: ProvidesUserContext = DependsOnTrans):
diff --git a/lib/galaxy/webapps/galaxy/api/remote_files.py b/lib/galaxy/webapps/galaxy/api/remote_files.py
index 75059d5cbdf..31dcae1137f 100644
--- a/lib/galaxy/webapps/galaxy/api/remote_files.py
+++ b/lib/galaxy/webapps/galaxy/api/remote_files.py
@@ -5,7 +5,6 @@ API operations on remote files.
import logging
from typing import (
Annotated,
- Optional,
)
from fastapi import (
@@ -41,7 +40,7 @@ TargetQueryParam: str = Query(
description=("The source to load datasets from. Possible values: ftpdir, userdir, importdir"),
)
-FormatQueryParam: Optional[RemoteFilesFormat] = Query(
+FormatQueryParam: RemoteFilesFormat | None = Query(
title="Response format",
description=(
"The requested format of returned data. Either `flat` to simply list all the files"
@@ -50,14 +49,14 @@ FormatQueryParam: Optional[RemoteFilesFormat] = Query(
),
)
-RecursiveQueryParam: Optional[bool] = Query(
+RecursiveQueryParam: bool | None = Query(
title="Recursive",
description=(
"Whether to recursively lists all sub-directories. This will be `True` by default depending on the `target`."
),
)
-DisableModeQueryParam: Optional[RemoteFilesDisableMode] = Query(
+DisableModeQueryParam: RemoteFilesDisableMode | None = Query(
title="Disable mode",
description=(
"(This only applies when `format` is `jstree`)"
@@ -66,7 +65,7 @@ DisableModeQueryParam: Optional[RemoteFilesDisableMode] = Query(
),
)
-WriteIntentQueryParam: Optional[bool] = Query(
+WriteIntentQueryParam: bool | None = Query(
title="Write Intent",
description=(
"Whether the query is made with the intention of writing to the source."
@@ -74,7 +73,7 @@ WriteIntentQueryParam: Optional[bool] = Query(
),
)
-BrowsableQueryParam: Optional[bool] = Query(
+BrowsableQueryParam: bool | None = Query(
title="Browsable filesources only",
description=(
"Whether to return browsable filesources only. The default is `True`, which will omit filesources"
@@ -132,17 +131,17 @@ class FastAPIRemoteFiles:
response: Response,
user_ctx: ProvidesUserContext = DependsOnTrans,
target: Annotated[str, TargetQueryParam] = RemoteFilesTarget.ftpdir,
- format: Annotated[Optional[RemoteFilesFormat], FormatQueryParam] = RemoteFilesFormat.uri,
- recursive: Annotated[Optional[bool], RecursiveQueryParam] = None,
- disable: Annotated[Optional[RemoteFilesDisableMode], DisableModeQueryParam] = None,
+ format: Annotated[RemoteFilesFormat | None, FormatQueryParam] = RemoteFilesFormat.uri,
+ recursive: Annotated[bool | None, RecursiveQueryParam] = None,
+ disable: Annotated[RemoteFilesDisableMode | None, DisableModeQueryParam] = None,
writeable: Annotated[
- Optional[bool], Query(description="Deprecated, please use `write_intent` instead.", deprecated=True)
+ bool | None, Query(description="Deprecated, please use `write_intent` instead.", deprecated=True)
] = None,
- write_intent: Annotated[Optional[bool], WriteIntentQueryParam] = None,
- limit: Annotated[Optional[int], LimitQueryParam] = None,
- offset: Annotated[Optional[int], OffsetQueryParam] = None,
- query: Annotated[Optional[str], SearchQueryParam] = None,
- sort_by: Annotated[Optional[str], SortByQueryParam] = None,
+ write_intent: Annotated[bool | None, WriteIntentQueryParam] = None,
+ limit: Annotated[int | None, LimitQueryParam] = None,
+ offset: Annotated[int | None, OffsetQueryParam] = None,
+ query: Annotated[str | None, SearchQueryParam] = None,
+ sort_by: Annotated[str | None, SortByQueryParam] = None,
) -> AnyRemoteFilesListResponse:
"""Lists all remote files available to the user from different sources.
@@ -162,9 +161,9 @@ class FastAPIRemoteFiles:
def plugins(
self,
user_ctx: ProvidesUserContext = DependsOnTrans,
- browsable_only: Annotated[Optional[bool], BrowsableQueryParam] = True,
- include_kind: Annotated[Optional[list[PluginKind]], IncludeKindQueryParam] = None,
- exclude_kind: Annotated[Optional[list[PluginKind]], ExcludeKindQueryParam] = None,
+ browsable_only: Annotated[bool | None, BrowsableQueryParam] = True,
+ include_kind: Annotated[list[PluginKind] | None, IncludeKindQueryParam] = None,
+ exclude_kind: Annotated[list[PluginKind] | None, ExcludeKindQueryParam] = None,
) -> FilesSourcePluginList:
"""Display plugin information for each of the gxfiles:// URI targets available."""
return self.manager.get_files_source_plugins(
diff --git a/lib/galaxy/webapps/galaxy/api/roles.py b/lib/galaxy/webapps/galaxy/api/roles.py
index 59cde92f88b..c05a2af3e41 100644
--- a/lib/galaxy/webapps/galaxy/api/roles.py
+++ b/lib/galaxy/webapps/galaxy/api/roles.py
@@ -3,7 +3,6 @@ API operations on Role objects.
"""
import logging
-from typing import Optional
from fastapi import (
Body,
@@ -26,18 +25,18 @@ from galaxy.webapps.galaxy.services.roles import RolesService
log = logging.getLogger(__name__)
-SearchRolesQueryParam: Optional[str] = Query(
+SearchRolesQueryParam: str | None = Query(
default=None,
title="Search filter",
description="Search by role name or user email (for private roles).",
)
-LimitRolesQueryParam: Optional[int] = Query(
+LimitRolesQueryParam: int | None = Query(
default=None,
ge=1,
title="Limit",
description="The maximum number of roles to return.",
)
-OffsetRolesQueryParam: Optional[int] = Query(
+OffsetRolesQueryParam: int | None = Query(
default=0,
ge=0,
title="Offset",
@@ -58,9 +57,9 @@ class FastAPIRoles:
def index(
self,
trans: ProvidesUserContext = DependsOnTrans,
- search: Optional[str] = SearchRolesQueryParam,
- limit: Optional[int] = LimitRolesQueryParam,
- offset: Optional[int] = OffsetRolesQueryParam,
+ search: str | None = SearchRolesQueryParam,
+ limit: int | None = LimitRolesQueryParam,
+ offset: int | None = OffsetRolesQueryParam,
) -> RoleListResponse:
return self.service.get_index(trans=trans, search=search, limit=limit, offset=offset)
diff --git a/lib/galaxy/webapps/galaxy/api/storage_cleaner.py b/lib/galaxy/webapps/galaxy/api/storage_cleaner.py
index 1d75b46891a..a319045a622 100644
--- a/lib/galaxy/webapps/galaxy/api/storage_cleaner.py
+++ b/lib/galaxy/webapps/galaxy/api/storage_cleaner.py
@@ -3,9 +3,6 @@ API operations on User storage management.
"""
import logging
-from typing import (
- Optional,
-)
from fastapi import (
Body,
@@ -36,7 +33,7 @@ log = logging.getLogger(__name__)
router = Router(tags=["storage management"])
-OrderQueryParam: Optional[StoredItemOrderBy] = Query(
+OrderQueryParam: StoredItemOrderBy | None = Query(
default=None,
title="Order",
description=(
@@ -67,9 +64,9 @@ class FastAPIStorageCleaner:
def discarded_histories(
self,
trans: ProvidesHistoryContext = DependsOnTrans,
- offset: Optional[int] = OffsetQueryParam,
- limit: Optional[int] = LimitQueryParam,
- order: Optional[StoredItemOrderBy] = OrderQueryParam,
+ offset: int | None = OffsetQueryParam,
+ limit: int | None = LimitQueryParam,
+ order: StoredItemOrderBy | None = OrderQueryParam,
) -> list[StoredItem]:
return self.service.get_discarded(trans, "history", offset, limit, order)
@@ -102,9 +99,9 @@ class FastAPIStorageCleaner:
def discarded_datasets(
self,
trans: ProvidesHistoryContext = DependsOnTrans,
- offset: Optional[int] = OffsetQueryParam,
- limit: Optional[int] = LimitQueryParam,
- order: Optional[StoredItemOrderBy] = OrderQueryParam,
+ offset: int | None = OffsetQueryParam,
+ limit: int | None = LimitQueryParam,
+ order: StoredItemOrderBy | None = OrderQueryParam,
) -> list[StoredItem]:
return self.service.get_discarded(trans, "dataset", offset, limit, order)
@@ -137,8 +134,8 @@ class FastAPIStorageCleaner:
def archived_histories(
self,
trans: ProvidesHistoryContext = DependsOnTrans,
- offset: Optional[int] = OffsetQueryParam,
- limit: Optional[int] = LimitQueryParam,
- order: Optional[StoredItemOrderBy] = OrderQueryParam,
+ offset: int | None = OffsetQueryParam,
+ limit: int | None = LimitQueryParam,
+ order: StoredItemOrderBy | None = OrderQueryParam,
) -> list[StoredItem]:
return self.service.get_archived(trans, "history", offset, limit, order)
diff --git a/lib/galaxy/webapps/galaxy/api/tool_data.py b/lib/galaxy/webapps/galaxy/api/tool_data.py
index 3d1f1a9abb8..a5c492f4244 100644
--- a/lib/galaxy/webapps/galaxy/api/tool_data.py
+++ b/lib/galaxy/webapps/galaxy/api/tool_data.py
@@ -1,5 +1,4 @@
from functools import partial
-from typing import Optional
import anyio
from fastapi import (
@@ -78,7 +77,7 @@ class FastAPIToolData:
require_admin=True,
)
def create(
- self, tool_data_file_path: Optional[str] = None, import_bundle_model: ImportToolDataBundle = Body(...)
+ self, tool_data_file_path: str | None = None, import_bundle_model: ImportToolDataBundle = Body(...)
) -> AsyncTaskResultSummary:
source = import_bundle_model.source
result = import_data_bundle.delay(tool_data_file_path=tool_data_file_path, **source.model_dump())
diff --git a/lib/galaxy/webapps/galaxy/api/tool_dependencies.py b/lib/galaxy/webapps/galaxy/api/tool_dependencies.py
index 79f01fe16ba..70fb93b3065 100644
--- a/lib/galaxy/webapps/galaxy/api/tool_dependencies.py
+++ b/lib/galaxy/webapps/galaxy/api/tool_dependencies.py
@@ -3,7 +3,6 @@ API operations allowing clients to manage tool dependencies.
"""
import logging
-from typing import Optional
from galaxy.managers.context import ProvidesAppContext
from galaxy.structured_app import StructuredApp
@@ -76,7 +75,7 @@ class ToolDependenciesAPIController(BaseGalaxyAPIController):
@require_admin
@expose_api
- def install_dependency(self, trans: ProvidesAppContext, id: Optional[str] = None, **kwds):
+ def install_dependency(self, trans: ProvidesAppContext, id: str | None = None, **kwds):
"""
POST /api/dependency_resolvers/{index}/dependency
POST /api/dependency_resolvers/dependency
diff --git a/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py b/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py
index dadf67048d1..ea823ec9664 100644
--- a/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py
+++ b/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py
@@ -3,7 +3,6 @@ import logging
from time import strftime
from typing import (
Annotated,
- Optional,
)
from fastapi import (
@@ -390,17 +389,17 @@ InstalledToolShedRepositoryIDPathParam = Annotated[
),
]
-NameQueryParam: Optional[str] = Query(default=None, title="Name", description="Filter by repository name.")
+NameQueryParam: str | None = Query(default=None, title="Name", description="Filter by repository name.")
-OwnerQueryParam: Optional[str] = Query(default=None, title="Owner", description="Filter by repository owner.")
+OwnerQueryParam: str | None = Query(default=None, title="Owner", description="Filter by repository owner.")
-ChangesetQueryParam: Optional[str] = Query(default=None, title="Changeset", description="Filter by changeset revision.")
+ChangesetQueryParam: str | None = Query(default=None, title="Changeset", description="Filter by changeset revision.")
-DeletedQueryParam: Optional[bool] = Query(
+DeletedQueryParam: bool | None = Query(
default=None, title="Deleted?", description="Filter by whether the repository has been deleted."
)
-UninstalledQueryParam: Optional[bool] = Query(
+UninstalledQueryParam: bool | None = Query(
default=None, title="Uninstalled?", description="Filter by whether the repository has been uninstalled."
)
@@ -417,11 +416,11 @@ class FastAPIToolShedRepositories:
)
def index(
self,
- name: Optional[str] = NameQueryParam,
- owner: Optional[str] = OwnerQueryParam,
- changeset: Optional[str] = ChangesetQueryParam,
- deleted: Optional[bool] = DeletedQueryParam,
- uninstalled: Optional[bool] = UninstalledQueryParam,
+ name: str | None = NameQueryParam,
+ owner: str | None = OwnerQueryParam,
+ changeset: str | None = ChangesetQueryParam,
+ deleted: bool | None = DeletedQueryParam,
+ uninstalled: bool | None = UninstalledQueryParam,
) -> list[InstalledToolShedRepository]:
request = InstalledToolShedRepositoryIndexRequest(
name=name,
@@ -438,7 +437,7 @@ class FastAPIToolShedRepositories:
response_description="A description of the state and updates message.",
require_admin=True,
)
- def check_for_updates(self, id: Optional[DecodedDatabaseIdField] = None) -> CheckForUpdatesResponse:
+ def check_for_updates(self, id: DecodedDatabaseIdField | None = None) -> CheckForUpdatesResponse:
return self.service.check_for_updates(id and int(id))
@router.get(
diff --git a/lib/galaxy/webapps/galaxy/api/tools.py b/lib/galaxy/webapps/galaxy/api/tools.py
index 9518c842e53..651c41cb2f3 100644
--- a/lib/galaxy/webapps/galaxy/api/tools.py
+++ b/lib/galaxy/webapps/galaxy/api/tools.py
@@ -8,7 +8,6 @@ from json import loads
from typing import (
Any,
cast,
- Optional,
)
from fastapi import (
@@ -138,7 +137,7 @@ FetchWorkbookCollectionTypeQueryParam: FetchWorkbookCollectionType = Query(
title="Collection Type",
description="Generate workbook for specified collection type (not all collection types are supported)",
)
-FetchWorkbookFilenameQueryParam: Optional[str] = Query(
+FetchWorkbookFilenameQueryParam: str | None = Query(
None,
description="Filename of the workbook download to generate",
)
@@ -153,10 +152,10 @@ ToolIDPathParam: str = Path(
title="Tool ID",
description="The tool ID for the lineage stored in Galaxy's toolbox.",
)
-ToolVersionQueryParam: Optional[str] = Query(default=None, title="Tool Version", description="")
+ToolVersionQueryParam: str | None = Query(default=None, title="Tool Version", description="")
-async def get_files(request: Request, files: Optional[list[UploadFile]] = None):
+async def get_files(request: Request, files: list[UploadFile] | None = None):
# FastAPI's UploadFile is a very light wrapper around starlette's UploadFile
files2: list[StarletteUploadFile] = cast(list[StarletteUploadFile], files or [])
if not files2:
@@ -200,7 +199,7 @@ class FetchTools:
trans: ProvidesHistoryContext = DependsOnTrans,
type: FetchWorkbookType = FetchWorkbookTypeQueryParam,
collection_type: FetchWorkbookCollectionType = FetchWorkbookCollectionTypeQueryParam,
- filename: Optional[str] = FetchWorkbookFilenameQueryParam,
+ filename: str | None = FetchWorkbookFilenameQueryParam,
):
generate_request = GenerateFetchWorkbookRequest(
type=type,
@@ -328,7 +327,7 @@ class FetchTools:
def tool_inputs(
self,
tool_id: str = ToolIDPathParam,
- tool_version: Optional[str] = ToolVersionQueryParam,
+ tool_version: str | None = ToolVersionQueryParam,
trans: ProvidesHistoryContext = DependsOnTrans,
) -> list[ToolParameterT]:
tool_run_ref = ToolRunReference(tool_id=tool_id, tool_version=tool_version, tool_uuid=None)
@@ -359,7 +358,7 @@ class FetchTools:
self,
trans: ProvidesUserContext = DependsOnTrans,
uuid: UUID4 = LandingUuidPathParam,
- payload: Optional[ClaimLandingPayload] = Body(...),
+ payload: ClaimLandingPayload | None = Body(...),
) -> ToolLandingRequest:
return self.landing_manager.claim_tool_landing_request(trans, uuid, payload)
@@ -380,7 +379,7 @@ class FetchTools:
def tool_state_request(
self,
tool_id: str = ToolIDPathParam,
- tool_version: Optional[str] = ToolVersionQueryParam,
+ tool_version: str | None = ToolVersionQueryParam,
trans: ProvidesHistoryContext = DependsOnTrans,
) -> Response:
tool_run_ref = ToolRunReference(tool_id=tool_id, tool_version=tool_version, tool_uuid=None)
@@ -398,7 +397,7 @@ class FetchTools:
def tool_state_landing_request(
self,
tool_id: str = ToolIDPathParam,
- tool_version: Optional[str] = ToolVersionQueryParam,
+ tool_version: str | None = ToolVersionQueryParam,
trans: ProvidesHistoryContext = DependsOnTrans,
) -> Response:
tool_run_ref = ToolRunReference(tool_id=tool_id, tool_version=tool_version, tool_uuid=None)
@@ -416,7 +415,7 @@ class FetchTools:
def tool_state_test_case_xml(
self,
tool_id: str = ToolIDPathParam,
- tool_version: Optional[str] = ToolVersionQueryParam,
+ tool_version: str | None = ToolVersionQueryParam,
trans: ProvidesHistoryContext = DependsOnTrans,
) -> Response:
tool_run_ref = ToolRunReference(tool_id=tool_id, tool_version=tool_version, tool_uuid=None)
@@ -788,7 +787,7 @@ class ToolsController(BaseGalaxyAPIController, UsesVisualizationMixin):
lineage_dict = tool.lineage.to_dict()
else:
lineage_dict = None
- tool_shed_dependencies_dict: Optional[list] = None
+ tool_shed_dependencies_dict: list | None = None
if tool_shed_dependencies := tool.installed_tool_dependencies:
tool_shed_dependencies_dict = list(map(to_dict, tool_shed_dependencies))
return {
@@ -955,7 +954,7 @@ class ToolsController(BaseGalaxyAPIController, UsesVisualizationMixin):
return self.service._create(trans, payload, **kwd)
-def validate_not_protected(tool_id: Optional[str]):
+def validate_not_protected(tool_id: str | None):
if tool_id in PROTECTED_TOOLS:
raise exceptions.RequestParameterInvalidException(
f"Cannot execute tool [{tool_id}] directly, must use alternative endpoint."
@@ -971,7 +970,7 @@ def _kwd_or_payload(kwd: dict[str, Any]) -> dict[str, Any]:
return kwd
-def _parse_options_pagination(value: Any) -> Optional[OptionsPaginationT]:
+def _parse_options_pagination(value: Any) -> OptionsPaginationT | None:
"""Accept ``options_pagination`` as a dict (POST body) or JSON-encoded string
(GET query param). Returns ``None`` if not provided. Server-side clamps are
applied later in ``_normalize_pagination`` so individual entries don't need
diff --git a/lib/galaxy/webapps/galaxy/api/users.py b/lib/galaxy/webapps/galaxy/api/users.py
index 538b27f04aa..f936a77c330 100644
--- a/lib/galaxy/webapps/galaxy/api/users.py
+++ b/lib/galaxy/webapps/galaxy/api/users.py
@@ -9,8 +9,6 @@ import re
from typing import (
Annotated,
Any,
- Optional,
- Union,
)
from fastapi import (
@@ -150,7 +148,7 @@ CustomBuildCreationBody = Body(
default=..., title="Add custom build", description="The values to add a new custom build."
)
UserCreationBody = Body(default=..., title="Create User", description="The values to add create a user.")
-AnyUserModel = Union[DetailedUserModel, AnonUserModel]
+AnyUserModel = DetailedUserModel | AnonUserModel
@router.cbv
@@ -207,9 +205,9 @@ class FastAPIUsers:
def index_deleted(
self,
trans: ProvidesUserContext = DependsOnTrans,
- f_email: Optional[str] = FilterEmailQueryParam,
- f_name: Optional[str] = FilterNameQueryParam,
- f_any: Optional[str] = FilterAnyQueryParam,
+ f_email: str | None = FilterEmailQueryParam,
+ f_name: str | None = FilterNameQueryParam,
+ f_any: str | None = FilterAnyQueryParam,
) -> list[MaybeLimitedUserModel]:
return self.service.get_index(trans=trans, deleted=True, f_email=f_email, f_name=f_name, f_any=f_any)
@@ -337,8 +335,8 @@ class FastAPIUsers:
trans: ProvidesUserContext = DependsOnTrans,
user_id: FlexibleUserIdType = FlexibleUserIdPathParam,
label: str = QuotaSourceLabelPathParam,
- ) -> Optional[UserQuotaUsage]:
- effective_label: Optional[str] = label
+ ) -> UserQuotaUsage | None:
+ effective_label: str | None = label
if label == "__null__":
effective_label = None
if user := self.service.get_user_full(trans, user_id, False):
@@ -593,7 +591,7 @@ class FastAPIUsers:
def create(
self,
trans: ProvidesUserContext = DependsOnTrans,
- payload: Union[UserCreationPayload, RemoteUserCreationPayload] = UserCreationBody,
+ payload: UserCreationPayload | RemoteUserCreationPayload = UserCreationBody,
) -> CreatedUserModel:
if isinstance(payload, UserCreationPayload):
email = payload.email
@@ -634,13 +632,11 @@ class FastAPIUsers:
self,
trans: ProvidesUserContext = DependsOnTrans,
deleted: bool = UsersDeletedQueryParam,
- f_email: Optional[str] = FilterEmailQueryParam,
- f_name: Optional[str] = FilterNameQueryParam,
- f_any: Optional[str] = FilterAnyQueryParam,
- limit: Optional[int] = Query(
- default=None, ge=1, title="Limit", description="Maximum number of users to return."
- ),
- offset: Optional[int] = Query(default=0, ge=0, title="Offset", description="Number of users to skip."),
+ f_email: str | None = FilterEmailQueryParam,
+ f_name: str | None = FilterNameQueryParam,
+ f_any: str | None = FilterAnyQueryParam,
+ limit: int | None = Query(default=None, ge=1, title="Limit", description="Maximum number of users to return."),
+ offset: int | None = Query(default=0, ge=0, title="Offset", description="Number of users to skip."),
) -> list[MaybeLimitedUserModel]:
return self.service.get_index(
trans=trans, deleted=deleted, f_email=f_email, f_name=f_name, f_any=f_any, limit=limit, offset=offset
@@ -655,7 +651,7 @@ class FastAPIUsers:
self,
trans: ProvidesHistoryContext = DependsOnTrans,
user_id: FlexibleUserIdType = FlexibleUserIdPathParam,
- deleted: Optional[bool] = UserDeletedQueryParam,
+ deleted: bool | None = UserDeletedQueryParam,
) -> AnyUserModel:
user_deleted = deleted or False
return self.service.show_user(trans=trans, user_id=user_id, deleted=user_deleted)
@@ -668,7 +664,7 @@ class FastAPIUsers:
trans: ProvidesUserContext = DependsOnTrans,
user_id: FlexibleUserIdType = FlexibleUserIdPathParam,
payload: UserUpdatePayload = UserUpdateBody,
- deleted: Optional[bool] = UserDeletedQueryParam,
+ deleted: bool | None = UserDeletedQueryParam,
) -> DetailedUserModel:
deleted = deleted or False
current_user = trans.user
@@ -693,7 +689,7 @@ class FastAPIUsers:
description="Whether to definitely remove this user. Only deleted users can be purged.",
),
] = False,
- payload: Optional[UserDeletionPayload] = None,
+ payload: UserDeletionPayload | None = None,
) -> DetailedUserModel:
user_to_update = self.service.user_manager.by_id(user_id)
assert user_to_update is not None
@@ -950,7 +946,11 @@ class UserAPIController(BaseGalaxyAPIController, UsesTagsMixin, BaseUIController
if "email" in payload:
email = payload.get("email")
self.user_manager.update_email(
- trans, user, email, commit=False, send_activation_email=True # commit at the end of the handler
+ trans,
+ user,
+ email,
+ commit=False,
+ send_activation_email=True, # commit at the end of the handler
)
# Update public name
if "username" in payload:
diff --git a/lib/galaxy/webapps/galaxy/api/visualizations.py b/lib/galaxy/webapps/galaxy/api/visualizations.py
index eadce18344a..bcea0cac127 100644
--- a/lib/galaxy/webapps/galaxy/api/visualizations.py
+++ b/lib/galaxy/webapps/galaxy/api/visualizations.py
@@ -8,7 +8,6 @@ may change often.
import logging
from typing import (
Annotated,
- Optional,
)
from fastapi import (
@@ -60,7 +59,7 @@ DeletedQueryParam: bool = Query(
default=False, title="Display deleted", description="Whether to include deleted visualizations in the result."
)
-UserIdQueryParam: Optional[DecodedDatabaseIdField] = Query(
+UserIdQueryParam: DecodedDatabaseIdField | None = Query(
default=None,
title="Encoded user ID to restrict query to, must be own id if not an admin user",
)
@@ -72,7 +71,7 @@ query_tags = [
IndexQueryTag("user", "The visualization's owner's username.", "u"),
]
-SearchQueryParam: Optional[str] = search_query_param(
+SearchQueryParam: str | None = search_query_param(
model_name="Visualization",
tags=query_tags,
free_text_fields=["title", "slug", "tag", "type"],
@@ -121,15 +120,15 @@ class FastAPIVisualizations:
response: Response,
trans: ProvidesUserContext = DependsOnTrans,
deleted: bool = DeletedQueryParam,
- limit: Optional[int] = LimitQueryParam,
- offset: Optional[int] = OffsetQueryParam,
- user_id: Optional[DecodedDatabaseIdField] = UserIdQueryParam,
+ limit: int | None = LimitQueryParam,
+ offset: int | None = OffsetQueryParam,
+ user_id: DecodedDatabaseIdField | None = UserIdQueryParam,
show_own: bool = ShowOwnQueryParam,
show_published: bool = ShowPublishedQueryParam,
show_shared: bool = ShowSharedQueryParam,
sort_by: VisualizationSortByEnum = SortByQueryParam,
sort_desc: bool = SortDescQueryParam,
- search: Optional[str] = SearchQueryParam,
+ search: str | None = SearchQueryParam,
) -> VisualizationSummaryList:
payload = VisualizationIndexQueryPayload.model_construct(
deleted=deleted,
@@ -254,7 +253,7 @@ class FastAPIVisualizations:
def create(
self,
payload: VisualizationCreatePayload = Body(...),
- import_id: Optional[DecodedDatabaseIdField] = Query(
+ import_id: DecodedDatabaseIdField | None = Query(
None, title="Import ID", description="The encoded database identifier of the Visualization to import."
),
trans: ProvidesUserContext = DependsOnTrans,
@@ -275,5 +274,5 @@ class FastAPIVisualizations:
id: VisualizationIdPathParam,
payload: VisualizationUpdatePayload = Body(...),
trans: ProvidesUserContext = DependsOnTrans,
- ) -> Optional[VisualizationUpdateResponse]:
+ ) -> VisualizationUpdateResponse | None:
return self.service.update(trans, id, payload)
diff --git a/lib/galaxy/webapps/galaxy/api/wes.py b/lib/galaxy/webapps/galaxy/api/wes.py
index 7e4972f5633..925a40c708f 100644
--- a/lib/galaxy/webapps/galaxy/api/wes.py
+++ b/lib/galaxy/webapps/galaxy/api/wes.py
@@ -3,7 +3,6 @@
import logging
from typing import (
Annotated,
- Optional,
)
from fastapi import (
@@ -71,15 +70,15 @@ class WesApi:
def submit_run(
self,
trans: ProvidesUserContext = DependsOnTrans,
- workflow_params: Optional[str] = Form(None),
+ workflow_params: str | None = Form(None),
workflow_type: str = Form(...),
workflow_type_version: str = Form(...),
- workflow_url: Optional[str] = Form(None),
- workflow_engine_parameters: Optional[str] = Form(None),
- workflow_engine: Optional[str] = Form(None),
- workflow_engine_version: Optional[str] = Form(None),
- tags: Optional[str] = Form(None),
- workflow_attachment: Optional[UploadFile] = File(None),
+ workflow_url: str | None = Form(None),
+ workflow_engine_parameters: str | None = Form(None),
+ workflow_engine: str | None = Form(None),
+ workflow_engine_version: str | None = Form(None),
+ tags: str | None = Form(None),
+ workflow_attachment: UploadFile | None = File(None),
) -> RunId:
"""Submit a new workflow run.
diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py
index 89229ce3322..e4e7b233f74 100644
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -9,8 +9,6 @@ from io import BytesIO
from typing import (
Annotated,
Any,
- Optional,
- Union,
)
from fastapi import (
@@ -785,7 +783,7 @@ WorkflowInvocationStepIDPathParam = Annotated[
]
InvocationsInstanceQueryParam = Annotated[
- Optional[bool],
+ bool | None,
Query(
title="Instance",
description="Is provided workflow id for Workflow instead of StoredWorkflow?",
@@ -793,7 +791,7 @@ InvocationsInstanceQueryParam = Annotated[
]
MultiTypeWorkflowIDPathParam = Annotated[
- Union[UUID4, UUID1, DecodedDatabaseIdField],
+ UUID4 | UUID1 | DecodedDatabaseIdField,
Path(
...,
title="Workflow ID",
@@ -815,41 +813,41 @@ MissingToolsQueryParam: bool = Query(
description="Whether to include a list of missing tools per workflow entry",
)
-ShowPublishedQueryParam: Optional[bool] = Query(default=None, title="Include published workflows.", description="")
+ShowPublishedQueryParam: bool | None = Query(default=None, title="Include published workflows.", description="")
-ShowSharedQueryParam: Optional[bool] = Query(
+ShowSharedQueryParam: bool | None = Query(
default=None, title="Include workflows shared with authenticated user.", description=""
)
-SortByQueryParam: Optional[WorkflowSortByEnum] = Query(
+SortByQueryParam: WorkflowSortByEnum | None = Query(
default=None,
title="Sort workflow index by this attribute",
description="In unspecified, default ordering depends on other parameters but generally the user's own workflows appear first based on update time",
)
-SortDescQueryParam: Optional[bool] = Query(
+SortDescQueryParam: bool | None = Query(
default=None,
title="Sort Descending",
description="Sort in descending order?",
)
-LimitQueryParam: Optional[int] = Query(default=None, ge=1, title="Limit number of queries.")
+LimitQueryParam: int | None = Query(default=None, ge=1, title="Limit number of queries.")
-OffsetQueryParam: Optional[int] = Query(
+OffsetQueryParam: int | None = Query(
default=0,
ge=0,
title="Number of workflows to skip in sorted query (to enable pagination).",
)
InstanceQueryParam = Annotated[
- Optional[bool],
+ bool | None,
Query(
title="True when fetching by Workflow ID, False when fetching by StoredWorkflow ID.",
),
]
LegacyQueryParam = Annotated[
- Optional[bool],
+ bool | None,
Query(
title="Legacy",
description="Use the legacy workflow format.",
@@ -857,7 +855,7 @@ LegacyQueryParam = Annotated[
]
VersionQueryParam = Annotated[
- Optional[int],
+ int | None,
Query(
title="Version",
description="The version of the workflow to fetch.",
@@ -894,7 +892,7 @@ query_tags = [
),
]
-SearchQueryParam: Optional[str] = search_query_param(
+SearchQueryParam: str | None = search_query_param(
model_name="Stored Workflow",
tags=query_tags,
free_text_fields=["name", "tag", "user"],
@@ -942,13 +940,13 @@ class FastAPIWorkflows:
show_deleted: bool = DeletedQueryParam,
show_hidden: bool = HiddenQueryParam,
missing_tools: bool = MissingToolsQueryParam,
- show_published: Optional[bool] = ShowPublishedQueryParam,
- show_shared: Optional[bool] = ShowSharedQueryParam,
- sort_by: Optional[WorkflowSortByEnum] = SortByQueryParam,
- sort_desc: Optional[bool] = SortDescQueryParam,
- limit: Optional[int] = LimitQueryParam,
- offset: Optional[int] = OffsetQueryParam,
- search: Optional[str] = SearchQueryParam,
+ show_published: bool | None = ShowPublishedQueryParam,
+ show_shared: bool | None = ShowSharedQueryParam,
+ sort_by: WorkflowSortByEnum | None = SortByQueryParam,
+ sort_desc: bool | None = SortDescQueryParam,
+ limit: int | None = LimitQueryParam,
+ offset: int | None = OffsetQueryParam,
+ search: str | None = SearchQueryParam,
skip_step_counts: bool = SkipStepCountsQueryParam,
) -> list[dict[str, Any]]:
"""Lists stored workflows viewable by the user."""
@@ -1126,7 +1124,7 @@ class FastAPIWorkflows:
payload: InvokeWorkflowBody,
workflow_id: MultiTypeWorkflowIDPathParam,
trans: ProvidesHistoryContext = DependsOnTrans,
- ) -> Union[WorkflowInvocationResponse, list[WorkflowInvocationResponse]]:
+ ) -> WorkflowInvocationResponse | list[WorkflowInvocationResponse]:
return self.service.invoke_workflow(trans, workflow_id, payload)
@router.get(
@@ -1162,11 +1160,11 @@ class FastAPIWorkflows:
def get_workflow_menu(
self,
trans: ProvidesUserContext = DependsOnTrans,
- show_deleted: Optional[bool] = DeletedQueryParam,
- show_hidden: Optional[bool] = HiddenQueryParam,
- missing_tools: Optional[bool] = MissingToolsQueryParam,
- show_published: Optional[bool] = ShowPublishedQueryParam,
- show_shared: Optional[bool] = ShowSharedQueryParam,
+ show_deleted: bool | None = DeletedQueryParam,
+ show_hidden: bool | None = HiddenQueryParam,
+ missing_tools: bool | None = MissingToolsQueryParam,
+ show_published: bool | None = ShowPublishedQueryParam,
+ show_shared: bool | None = ShowSharedQueryParam,
):
payload = WorkflowIndexPayload(
show_published=show_published,
@@ -1208,7 +1206,7 @@ class FastAPIWorkflows:
self,
trans: ProvidesUserContext = DependsOnTrans,
uuid: UUID4 = LandingUuidPathParam,
- payload: Optional[ClaimLandingPayload] = Body(...),
+ payload: ClaimLandingPayload | None = Body(...),
user: model.User = DependsOnUser,
) -> WorkflowLandingRequest:
return self.landing_manager.claim_workflow_landing_request(trans, uuid, payload)
@@ -1244,7 +1242,7 @@ LegacyJobStateQueryParam = Annotated[
]
WorkflowIdQueryParam = Annotated[
- Optional[DecodedDatabaseIdField],
+ DecodedDatabaseIdField | None,
Query(
title="Workflow ID",
description="Return only invocations for this Workflow ID",
@@ -1252,7 +1250,7 @@ WorkflowIdQueryParam = Annotated[
]
HistoryIdQueryParam = Annotated[
- Optional[DecodedDatabaseIdField],
+ DecodedDatabaseIdField | None,
Query(
title="History ID",
description="Return only invocations for this History ID",
@@ -1260,7 +1258,7 @@ HistoryIdQueryParam = Annotated[
]
JobIdQueryParam = Annotated[
- Optional[DecodedDatabaseIdField],
+ DecodedDatabaseIdField | None,
Query(
title="Job ID",
description="Return only invocations for this Job ID",
@@ -1268,7 +1266,7 @@ JobIdQueryParam = Annotated[
]
UserIdQueryParam = Annotated[
- Optional[DecodedDatabaseIdField],
+ DecodedDatabaseIdField | None,
Query(
title="User ID",
description="Return invocations for this User ID.",
@@ -1276,7 +1274,7 @@ UserIdQueryParam = Annotated[
]
InvocationsSortByQueryParam = Annotated[
- Optional[InvocationSortByEnum],
+ InvocationSortByEnum | None,
Query(
title="Sort By",
description="Sort Workflow Invocations by this attribute",
@@ -1292,7 +1290,7 @@ InvocationsSortDescQueryParam = Annotated[
]
InvocationsIncludeTerminalQueryParam = Annotated[
- Optional[bool],
+ bool | None,
Query(
title="Include Terminal",
description="Set to false to only include terminal Invocations.",
@@ -1300,7 +1298,7 @@ InvocationsIncludeTerminalQueryParam = Annotated[
]
InvocationsLimitQueryParam = Annotated[
- Optional[int],
+ int | None,
Query(
ge=1,
le=100,
@@ -1310,7 +1308,7 @@ InvocationsLimitQueryParam = Annotated[
]
InvocationsOffsetQueryParam = Annotated[
- Optional[int],
+ int | None,
Query(
ge=0,
title="Offset",
@@ -1732,11 +1730,9 @@ class FastAPIInvocations:
invocation_id: InvocationIDPathParam,
trans: ProvidesUserContext = DependsOnTrans,
) -> list[
- Union[
- InvocationStepJobsResponseStepModel,
- InvocationStepJobsResponseJobModel,
- InvocationStepJobsResponseCollectionJobsModel,
- ]
+ InvocationStepJobsResponseStepModel
+ | InvocationStepJobsResponseJobModel
+ | InvocationStepJobsResponseCollectionJobsModel
]:
"""
Warning: We allow anyone to fetch job state information about any object they
@@ -1773,11 +1769,9 @@ class FastAPIInvocations:
invocation_id: InvocationIDPathParam,
trans: ProvidesUserContext = DependsOnTrans,
) -> list[
- Union[
- InvocationStepJobsResponseStepModel,
- InvocationStepJobsResponseJobModel,
- InvocationStepJobsResponseCollectionJobsModel,
- ]
+ InvocationStepJobsResponseStepModel
+ | InvocationStepJobsResponseJobModel
+ | InvocationStepJobsResponseCollectionJobsModel
]:
"""An alias for `GET /api/invocations/{invocation_id}/step_jobs_summary`. `workflow_id` is ignored."""
return self.invocation_step_jobs_summary(trans=trans, invocation_id=invocation_id)
@@ -1834,7 +1828,7 @@ class FastAPIInvocations:
self,
invocation_id: InvocationIDPathParam,
trans: ProvidesUserContext = DependsOnTrans,
- ) -> Optional[WorkflowInvocationCompletionResponse]:
+ ) -> WorkflowInvocationCompletionResponse | None:
"""
Get completion details for a workflow invocation.
diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py
index 166ea76c29a..c68a985bbca 100644
--- a/lib/galaxy/webapps/galaxy/buildapp.py
+++ b/lib/galaxy/webapps/galaxy/buildapp.py
@@ -7,7 +7,6 @@ import logging
import sys
import threading
import traceback
-from typing import Optional
from paste import httpexceptions
@@ -34,9 +33,7 @@ log = logging.getLogger(__name__)
class GalaxyWebApplication(galaxy.webapps.base.webapp.WebApplication):
injection_aware = True
- def __init__(
- self, galaxy_app: MinimalApp, session_cookie: str = "galaxysession", name: Optional[str] = None
- ) -> None:
+ def __init__(self, galaxy_app: MinimalApp, session_cookie: str = "galaxysession", name: str | None = None) -> None:
super().__init__(galaxy_app, session_cookie, name)
self.session_factories.append(galaxy_app.install_model)
diff --git a/lib/galaxy/webapps/galaxy/controllers/admin.py b/lib/galaxy/webapps/galaxy/controllers/admin.py
index 77cf315fbaa..e06a303c314 100644
--- a/lib/galaxy/webapps/galaxy/controllers/admin.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin.py
@@ -627,7 +627,7 @@ class AdminGalaxy(controller.BaseUIController):
trans.handle_user_logout()
trans.handle_user_login(user)
return trans.show_message(
- f"You are now logged in as {user.email}, return to the home page ",
+ f'You are now logged in as {user.email}, return to the home page ',
use_panels=True,
)
except Exception:
diff --git a/lib/galaxy/webapps/galaxy/controllers/page.py b/lib/galaxy/webapps/galaxy/controllers/page.py
index 1ea9e790c55..625270346a8 100644
--- a/lib/galaxy/webapps/galaxy/controllers/page.py
+++ b/lib/galaxy/webapps/galaxy/controllers/page.py
@@ -10,7 +10,6 @@ from galaxy.webapps.base.controller import (
class PageController(BaseUIController, SharableMixin, SharableItemSecurityMixin):
-
def __init__(self, app: StructuredApp):
super().__init__(app)
diff --git a/lib/galaxy/webapps/galaxy/controllers/user.py b/lib/galaxy/webapps/galaxy/controllers/user.py
index 16a9991a089..60f5fe7ef4f 100644
--- a/lib/galaxy/webapps/galaxy/controllers/user.py
+++ b/lib/galaxy/webapps/galaxy/controllers/user.py
@@ -233,9 +233,9 @@ class User(BaseUIController, UsesFormDefinitionsMixin):
username = trans.user.username
is_activation_sent = self.user_manager.send_activation_email(trans, email, username)
if is_activation_sent:
- message = f"This account has not been activated yet. The activation link has been sent again. Please check your email address {escape(email)} including the spam/trash folder. Return to the home page ."
+ message = f'This account has not been activated yet. The activation link has been sent again. Please check your email address {escape(email)} including the spam/trash folder. Return to the home page .'
else:
- message = f"This account has not been activated yet but we are unable to send the activation link. Please contact your local Galaxy administrator. Return to the home page ."
+ message = f'This account has not been activated yet but we are unable to send the activation link. Please contact your local Galaxy administrator. Return to the home page .'
if trans.app.config.error_email_to is not None:
message += f" Error contact: {trans.app.config.error_email_to}."
return message, is_activation_sent
diff --git a/lib/galaxy/webapps/galaxy/fast_app.py b/lib/galaxy/webapps/galaxy/fast_app.py
index 2cd53cc992d..f6440ca03af 100644
--- a/lib/galaxy/webapps/galaxy/fast_app.py
+++ b/lib/galaxy/webapps/galaxy/fast_app.py
@@ -338,8 +338,7 @@ def galaxy_rate_limit_key(request: Request) -> str:
api_key = request.headers.get("x-api-key") or request.query_params.get("key")
if api_key:
return f"api_key:{api_key}"
- session_key = request.cookies.get("galaxysession")
- if session_key:
+ if session_key := request.cookies.get("galaxysession"):
return f"session:{session_key}"
return get_remote_address(request)
diff --git a/lib/galaxy/webapps/galaxy/services/authenticate.py b/lib/galaxy/webapps/galaxy/services/authenticate.py
index a33ffd5e453..7387f012091 100644
--- a/lib/galaxy/webapps/galaxy/services/authenticate.py
+++ b/lib/galaxy/webapps/galaxy/services/authenticate.py
@@ -1,8 +1,6 @@
from base64 import b64decode
from typing import (
Any,
- Optional,
- Union,
)
from urllib.parse import unquote
@@ -19,7 +17,7 @@ from galaxy.util import (
)
from galaxy.web.framework.base import Request as GxRequest
-Request = Union[GxRequest, StartletteRequest]
+Request = GxRequest | StartletteRequest
class APIKeyResponse(BaseModel):
@@ -46,7 +44,7 @@ class AuthenticationService:
else:
raise exceptions.AuthenticationFailed("Invalid password.")
- def _decode_baseauth(self, encoded_str: Optional[Any]) -> tuple[str, str]:
+ def _decode_baseauth(self, encoded_str: Any | None) -> tuple[str, str]:
"""
Decode an encrypted HTTP basic authentication string. Returns a tuple of
the form (email, password), and raises a HTTPBadRequest exception if
diff --git a/lib/galaxy/webapps/galaxy/services/base.py b/lib/galaxy/webapps/galaxy/services/base.py
index 6b6e36abf19..ac735b18280 100644
--- a/lib/galaxy/webapps/galaxy/services/base.py
+++ b/lib/galaxy/webapps/galaxy/services/base.py
@@ -5,7 +5,6 @@ from typing import (
Any,
cast,
NamedTuple,
- Optional,
)
from galaxy.exceptions import (
@@ -73,7 +72,7 @@ class ServiceBase:
the required parameters and outputs of each operation.
"""
- def __init__(self, security: Optional[IdEncodingHelper] = None):
+ def __init__(self, security: IdEncodingHelper | None = None):
self._security = security
@property
@@ -84,11 +83,11 @@ class ServiceBase:
)
return self._security
- def decode_id(self, id: EncodedDatabaseIdField, kind: Optional[str] = None) -> int:
+ def decode_id(self, id: EncodedDatabaseIdField, kind: str | None = None) -> int:
"""Decodes a previously encoded database ID."""
return decode_with_security(self.security, id, kind=kind)
- def encode_id(self, id: int, kind: Optional[str] = None) -> EncodedDatabaseIdField:
+ def encode_id(self, id: int, kind: str | None = None) -> EncodedDatabaseIdField:
"""Encodes a raw database ID."""
return encode_with_security(self.security, id, kind=kind)
@@ -106,7 +105,7 @@ class ServiceBase:
"""
return self.security.encode_all_ids(rval, recursive=recursive)
- def build_order_by(self, manager: SortableManager, order_by_query: Optional[str] = None):
+ def build_order_by(self, manager: SortableManager, order_by_query: str | None = None):
"""Returns an ORM compatible order_by clause using the order attribute and the given manager.
The manager has to implement the `parse_order_by` function to support all the sortable model attributes."""
diff --git a/lib/galaxy/webapps/galaxy/services/credentials.py b/lib/galaxy/webapps/galaxy/services/credentials.py
index e6637930a90..78197b735ea 100644
--- a/lib/galaxy/webapps/galaxy/services/credentials.py
+++ b/lib/galaxy/webapps/galaxy/services/credentials.py
@@ -2,8 +2,6 @@ from collections.abc import Callable
from typing import (
Any,
cast,
- Optional,
- Union,
)
from sqlalchemy.orm import scoped_session
@@ -47,7 +45,7 @@ from galaxy.security.vault import UserVaultWrapper
from galaxy.structured_app import StructuredApp
from galaxy.tool_util.deps.requirements import CredentialsRequirement
-GetToolCredentialsDefinition = Callable[[User, str, str, str, str], Optional[CredentialsRequirement]]
+GetToolCredentialsDefinition = Callable[[User, str, str, str, str], CredentialsRequirement | None]
class CredentialsService:
@@ -68,11 +66,11 @@ class CredentialsService:
self,
trans: ProvidesUserContext,
user_id: FlexibleUserIdType,
- source_type: Optional[SOURCE_TYPE] = None,
- source_id: Optional[str] = None,
- source_version: Optional[str] = None,
+ source_type: SOURCE_TYPE | None = None,
+ source_id: str | None = None,
+ source_version: str | None = None,
include_definition: bool = False,
- ) -> Union[UserServiceCredentialsListResponse, ExtendedUserCredentialsListResponse]:
+ ) -> UserServiceCredentialsListResponse | ExtendedUserCredentialsListResponse:
"""Lists all credentials the user has provided (credentials themselves are not included)."""
user = self._ensure_user_access(trans, user_id)
return self._list_user_credentials(user, source_type, source_id, source_version, include_definition)
@@ -150,8 +148,8 @@ class CredentialsService:
self,
trans: ProvidesUserContext,
user_id: FlexibleUserIdType,
- user_credentials_id: Optional[DecodedDatabaseIdField] = None,
- group_id: Optional[DecodedDatabaseIdField] = None,
+ user_credentials_id: DecodedDatabaseIdField | None = None,
+ group_id: DecodedDatabaseIdField | None = None,
) -> None:
"""Deletes a specific credential group or all credentials for a specific service."""
user = self._ensure_user_access(trans, user_id)
@@ -240,7 +238,7 @@ class CredentialsService:
tool_version: str,
service_name: str,
service_version: str,
- ) -> Optional[CredentialsRequirement]:
+ ) -> CredentialsRequirement | None:
tool = self.app.toolbox.get_tool(tool_id, tool_version)
if not tool:
raise ObjectNotFound(f"Could not find tool with id '{tool_id}'.")
@@ -259,11 +257,11 @@ class CredentialsService:
def _list_user_credentials(
self,
user: User,
- source_type: Optional[SOURCE_TYPE] = None,
- source_id: Optional[str] = None,
- source_version: Optional[str] = None,
+ source_type: SOURCE_TYPE | None = None,
+ source_id: str | None = None,
+ source_version: str | None = None,
include_definition: bool = False,
- ) -> Union[UserServiceCredentialsListResponse, ExtendedUserCredentialsListResponse]:
+ ) -> UserServiceCredentialsListResponse | ExtendedUserCredentialsListResponse:
existing_user_credentials = self.credentials_manager.get_user_credentials(
user.id, source_type, source_id, source_version
)
diff --git a/lib/galaxy/webapps/galaxy/services/dataset_collections.py b/lib/galaxy/webapps/galaxy/services/dataset_collections.py
index cf1639910ef..c328ac93b5f 100644
--- a/lib/galaxy/webapps/galaxy/services/dataset_collections.py
+++ b/lib/galaxy/webapps/galaxy/services/dataset_collections.py
@@ -2,9 +2,7 @@ from io import BytesIO
from logging import getLogger
from typing import (
Literal,
- Optional,
TYPE_CHECKING,
- Union,
)
from pydantic import (
@@ -88,8 +86,8 @@ class DatasetCollectionAttributesResult(Model):
# Are the following fields really used/needed?
extension: str = Field(..., description="The dataset file extension.", examples=["txt"])
model_class: Literal["HistoryDatasetCollectionAssociation"] = ModelClassField("HistoryDatasetCollectionAssociation")
- dbkeys: Optional[set[str]]
- extensions: Optional[set[str]]
+ dbkeys: set[str] | None
+ extensions: set[str] | None
tags: TagCollection
@@ -114,7 +112,7 @@ class DatasetCollectionContentElements(RootModel):
class CreateWorkbookForCollectionApi(BaseModel):
column_definitions: list[SampleSheetColumnDefinitionModel] = ColumnDefinitionsField
- prefix_values: Optional[PrefixRowValuesT] = PrefixRowsField
+ prefix_values: PrefixRowValuesT | None = PrefixRowsField
class ParseWorkbookForCollectionApi(BaseModel):
@@ -136,7 +134,7 @@ class ParsedWorkbookCollection(BaseModel):
model_class: Literal["DatasetCollection"] = "DatasetCollection"
-ParsedWorkbookElementObject = Union[ParsedWorkbookHda, ParsedWorkbookCollection]
+ParsedWorkbookElementObject = ParsedWorkbookHda | ParsedWorkbookCollection
class ParsedWorkbookElement(BaseModel):
@@ -260,7 +258,7 @@ class DatasetCollectionsService(ServiceBase, UsesLibraryMixinItems):
"""
Returns information about a particular dataset collection.
"""
- dataset_collection_instance: Union[HistoryDatasetCollectionAssociation, LibraryDatasetCollectionAssociation]
+ dataset_collection_instance: HistoryDatasetCollectionAssociation | LibraryDatasetCollectionAssociation
if instance_type == "history":
dataset_collection_instance = self.collection_manager.get_dataset_collection_instance(trans, "history", id)
parent = dataset_collection_instance.history
@@ -280,7 +278,7 @@ class DatasetCollectionsService(ServiceBase, UsesLibraryMixinItems):
return rval
def dce_content(self, trans: ProvidesHistoryContext, dce_id: DecodedDatabaseIdField) -> DCESummary:
- dce: Optional[DatasetCollectionElement] = trans.model.session.get(DatasetCollectionElement, dce_id)
+ dce: DatasetCollectionElement | None = trans.model.session.get(DatasetCollectionElement, dce_id)
if not dce:
raise exceptions.ObjectNotFound("No DatasetCollectionElement found")
if not trans.user_is_admin:
@@ -296,8 +294,8 @@ class DatasetCollectionsService(ServiceBase, UsesLibraryMixinItems):
hdca_id: DecodedDatabaseIdField,
parent_id: DecodedDatabaseIdField,
instance_type: DatasetCollectionInstanceType = "history",
- limit: Optional[int] = None,
- offset: Optional[int] = None,
+ limit: int | None = None,
+ offset: int | None = None,
) -> DatasetCollectionContentElements:
"""
Shows direct child contents of indicated dataset collection parent id
diff --git a/lib/galaxy/webapps/galaxy/services/datasets.py b/lib/galaxy/webapps/galaxy/services/datasets.py
index d3f7f8ee8b3..e304177aeec 100644
--- a/lib/galaxy/webapps/galaxy/services/datasets.py
+++ b/lib/galaxy/webapps/galaxy/services/datasets.py
@@ -7,8 +7,6 @@ import os
from enum import Enum
from typing import (
Any,
- Optional,
- Union,
)
from pydantic import (
@@ -119,7 +117,7 @@ class DatasetContentType(str, Enum):
class ConcreteObjectStoreQuotaSourceDetails(Model):
- source: Optional[str] = Field(
+ source: str | None = Field(
description="The quota source label corresponding to the object store the dataset is stored in (or would be stored in)"
)
enabled: bool = Field(
@@ -128,16 +126,16 @@ class ConcreteObjectStoreQuotaSourceDetails(Model):
class DatasetStorageDetails(Model):
- object_store_id: Optional[str] = Field(
+ object_store_id: str | None = Field(
description="The identifier of the destination ObjectStore for this dataset.",
)
- name: Optional[str] = Field(
+ name: str | None = Field(
description="The display name of the destination ObjectStore for this dataset.",
)
- description: Optional[str] = Field(
+ description: str | None = Field(
description="A description of how this dataset is stored.",
)
- percent_used: Optional[float] = Field(
+ percent_used: float | None = Field(
description="The percentage indicating how full the store is.",
)
dataset_state: str = Field(
@@ -172,7 +170,7 @@ class DatasetInheritanceChainEntry(Model):
dep: str = Field(
description="Name of the source of the referenced dataset at this point of the inheritance chain.",
)
- user_id: Optional[EncodedDatabaseIdField] = Field(
+ user_id: EncodedDatabaseIdField | None = Field(
description="ID of the user who owns the referenced dataset.",
)
@@ -206,7 +204,7 @@ class DatasetExtraFiles(RootModel):
class DatasetTextContentDetails(Model):
- item_data: Optional[str] = Field(
+ item_data: str | None = Field(
description="First chunk of text content (maximum 1MB) of the dataset.",
)
truncated: bool = Field(
@@ -237,9 +235,9 @@ class DataMode(str, Enum):
class DataResult(Model):
data: list[Any]
- dataset_type: Optional[str] = None
- message: Optional[str] = None
- extra_info: Optional[Any] = None # Seems to be always None, deprecate?
+ dataset_type: str | None = None
+ message: str | None = None
+ extra_info: Any | None = None # Seems to be always None, deprecate?
class BamDataResult(DataResult):
@@ -251,7 +249,7 @@ class DeleteDatasetBatchPayload(Model):
datasets: list[DatasetSourceId] = Field(
description="The list of datasets IDs with their sources to be deleted/purged.",
)
- purge: Optional[bool] = Field(
+ purge: bool | None = Field(
default=False,
description=(
"Whether to permanently delete from disk the specified datasets. "
@@ -261,10 +259,10 @@ class DeleteDatasetBatchPayload(Model):
class ComputeDatasetHashPayload(Model):
- hash_function: Optional[HashFunctionNameEnum] = Field(
+ hash_function: HashFunctionNameEnum | None = Field(
default=HashFunctionNameEnum.md5, description="Hash function name to use to compute dataset hashes."
)
- extra_files_path: Optional[str] = Field(default=None, description="If set, extra files path to compute a hash for.")
+ extra_files_path: str | None = Field(default=None, description="If set, extra files path to compute a hash for.")
model_config = ConfigDict(use_enum_values=True)
@@ -288,7 +286,7 @@ class DeleteDatasetBatchResult(Model):
success_count: int = Field(
description="The number of datasets successfully processed.",
)
- errors: Optional[list[DatasetErrorMessage]] = Field(
+ errors: list[DatasetErrorMessage] | None = Field(
default=None,
description=(
"A list of dataset IDs and the corresponding error message if something "
@@ -333,7 +331,7 @@ class DatasetsService(ServiceBase, UsesVisualizationMixin):
def index(
self,
trans: ProvidesHistoryContext,
- history_id: Optional[DecodedDatabaseIdField],
+ history_id: DecodedDatabaseIdField | None,
serialization_params: SerializationParams,
filter_query_params: FilterQueryParams,
) -> tuple[list[AnyHistoryContentItem], int]:
@@ -377,7 +375,7 @@ class DatasetsService(ServiceBase, UsesVisualizationMixin):
dataset_id: DecodedDatabaseIdField,
hda_ldda: DatasetSourceType,
serialization_params: SerializationParams,
- data_type: Optional[RequestDataType] = None,
+ data_type: RequestDataType | None = None,
**extra_params,
):
"""
@@ -641,11 +639,11 @@ class DatasetsService(ServiceBase, UsesVisualizationMixin):
dataset_id: DecodedDatabaseIdField,
hda_ldda: DatasetSourceType = DatasetSourceType.hda,
preview: bool = False,
- filename: Optional[str] = None,
- to_ext: Optional[str] = None,
+ filename: str | None = None,
+ to_ext: str | None = None,
raw: bool = False,
- offset: Optional[int] = None,
- ck_size: Optional[int] = None,
+ offset: int | None = None,
+ ck_size: int | None = None,
**kwd,
):
"""
@@ -689,7 +687,7 @@ class DatasetsService(ServiceBase, UsesVisualizationMixin):
return rval, headers
def get_content_as_text(
- self, trans: ProvidesHistoryContext, dataset_id: DecodedDatabaseIdField, filename: Optional[str]
+ self, trans: ProvidesHistoryContext, dataset_id: DecodedDatabaseIdField, filename: str | None
) -> DatasetTextContentDetails:
"""Returns dataset content as Text."""
user = trans.user
@@ -875,9 +873,9 @@ class DatasetsService(ServiceBase, UsesVisualizationMixin):
self,
trans,
dataset: model.DatasetInstance,
- chrom: Optional[str] = None,
+ chrom: str | None = None,
retry: bool = False,
- ) -> Union[model.Dataset.conversion_messages, dict]:
+ ) -> model.Dataset.conversion_messages | dict:
"""
Init-like method that returns state of dataset's converted datasets.
Returns valid chroms for that dataset as well.
@@ -913,7 +911,7 @@ class DatasetsService(ServiceBase, UsesVisualizationMixin):
self,
trans,
dataset: model.DatasetInstance,
- query: Optional[str],
+ query: str | None,
) -> list[list[str]]:
"""
Returns features, locations in dataset that match query. Format is a
@@ -940,9 +938,9 @@ class DatasetsService(ServiceBase, UsesVisualizationMixin):
low: int,
high: int,
start_val: int = 0,
- max_vals: Optional[int] = None,
+ max_vals: int | None = None,
**kwargs,
- ) -> Union[model.Dataset.conversion_messages, BamDataResult, DataResult]:
+ ) -> model.Dataset.conversion_messages | BamDataResult | DataResult:
"""
Provides a block of data from a dataset.
"""
@@ -1043,7 +1041,7 @@ class DatasetsService(ServiceBase, UsesVisualizationMixin):
dataset,
provider=None,
**kwargs,
- ) -> Union[model.Dataset.conversion_messages, BamDataResult, DataResult]:
+ ) -> model.Dataset.conversion_messages | BamDataResult | DataResult:
"""
Uses original (raw) dataset to return data. This method is useful
when the dataset is not yet indexed and hence using data would
diff --git a/lib/galaxy/webapps/galaxy/services/events.py b/lib/galaxy/webapps/galaxy/services/events.py
index 690c93a60fa..4ede7642b3d 100644
--- a/lib/galaxy/webapps/galaxy/services/events.py
+++ b/lib/galaxy/webapps/galaxy/services/events.py
@@ -8,9 +8,6 @@ skipped; the stream still delivers other push events.
"""
from collections.abc import AsyncIterator
-from typing import (
- Optional,
-)
from galaxy.managers.context import ProvidesUserContext
from galaxy.managers.sse import (
@@ -36,7 +33,7 @@ class EventsService(ServiceBase):
def open_stream(
self,
user_context: ProvidesUserContext,
- last_event_id: Optional[str],
+ last_event_id: str | None,
is_disconnected: IsDisconnected,
) -> AsyncIterator[str]:
"""Open an SSE events stream.
diff --git a/lib/galaxy/webapps/galaxy/services/histories.py b/lib/galaxy/webapps/galaxy/services/histories.py
index 8697f5d71d3..a9613749d4f 100644
--- a/lib/galaxy/webapps/galaxy/services/histories.py
+++ b/lib/galaxy/webapps/galaxy/services/histories.py
@@ -10,8 +10,6 @@ from tempfile import (
from typing import (
cast,
Literal,
- Optional,
- Union,
)
from sqlalchemy import (
@@ -165,8 +163,8 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
trans: ProvidesHistoryContext,
serialization_params: SerializationParams,
filter_query_params: FilterQueryParams,
- deleted_only: Optional[bool] = False,
- all_histories: Optional[bool] = False,
+ deleted_only: bool | None = False,
+ all_histories: bool | None = False,
):
"""
Return a collection of histories for the current user. Additional filters can be applied.
@@ -214,7 +212,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
]
return rval
- def _get_deleted_filter(self, deleted: Optional[bool], filter_params: list[tuple[str, str, str]]):
+ def _get_deleted_filter(self, deleted: bool | None, filter_params: list[tuple[str, str, str]]):
# TODO: this should all be removed (along with the default) in v2
# support the old default of not-returning/filtering-out deleted histories
try:
@@ -244,7 +242,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
payload: HistoryIndexQueryPayload,
serialization_params: SerializationParams,
include_total_count: bool = False,
- ) -> tuple[list[AnyHistoryView], Union[int, None]]:
+ ) -> tuple[list[AnyHistoryView], int | None]:
"""Return a list of History accessible by the user
:rtype: list
@@ -378,7 +376,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
self,
trans: ProvidesHistoryContext,
serialization_params: SerializationParams,
- history_id: Optional[DecodedDatabaseIdField] = None,
+ history_id: DecodedDatabaseIdField | None = None,
):
"""
Returns detailed information about the history with the given encoded `id`. If no `id` is
@@ -404,12 +402,12 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
history_id: DecodedDatabaseIdField,
limit: int = 500,
include_deleted: bool = False,
- seed_src: Optional[NodeSrc] = None,
- seed_id: Optional[str] = None,
+ seed_src: NodeSrc | None = None,
+ seed_id: str | None = None,
direction: Literal["backward", "forward", "both"] = "both",
depth: int = 20,
- seed_scope_src: Optional[Literal["hda", "hdca"]] = None,
- seed_scope_id: Optional[str] = None,
+ seed_scope_src: Literal["hda", "hdca"] | None = None,
+ seed_scope_id: str | None = None,
) -> HistoryGraphResponse:
history = self.manager.get_accessible(history_id, trans.user, current_history=trans.history)
seed = self._build_node_ref("seed", seed_src, seed_id)
@@ -427,7 +425,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
)
@staticmethod
- def _build_node_ref(param: str, src: Optional[str], id: Optional[str]) -> Optional[NodeRef]:
+ def _build_node_ref(param: str, src: str | None, id: str | None) -> NodeRef | None:
if src is None and id is None:
return None
if src is None or id is None:
@@ -646,8 +644,8 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
trans: ProvidesHistoryContext,
history_id: DecodedDatabaseIdField,
use_tasks: bool = False,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
+ limit: int | None = None,
+ offset: int | None = None,
):
if use_tasks:
return self.history_export_manager.get_task_exports(trans, history_id, limit, offset)
@@ -657,7 +655,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
self,
trans,
history_id: DecodedDatabaseIdField,
- payload: Optional[ExportHistoryArchivePayload] = None,
+ payload: ExportHistoryArchivePayload | None = None,
) -> tuple[HistoryArchiveExportResult, bool]:
"""
start job (if needed) to create history export for corresponding
@@ -713,7 +711,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
self,
trans: ProvidesHistoryContext,
history_id: DecodedDatabaseIdField,
- jeha_id: Union[DecodedDatabaseIdField, LatestLiteral],
+ jeha_id: DecodedDatabaseIdField | LatestLiteral,
) -> model.JobExportHistoryArchive:
"""Returns the exported history archive information if it's ready
or raises an exception if not."""
@@ -788,14 +786,14 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
)
return serialized_history
- def _build_order_by(self, order: Optional[str]):
+ def _build_order_by(self, order: str | None):
return self.build_order_by(self.manager, order or DEFAULT_ORDER_BY)
def archive_history(
self,
trans: ProvidesHistoryContext,
history_id: DecodedDatabaseIdField,
- payload: Optional[ArchiveHistoryRequestPayload] = None,
+ payload: ArchiveHistoryRequestPayload | None = None,
) -> AnyArchivedHistoryView:
"""Marks the history with the given id as archived and optionally associates it with the given archive export record in the payload.
@@ -849,7 +847,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
}
def serialize_output(
- content, output_name: Optional[str] = None, expose_outputs: bool = False
+ content, output_name: str | None = None, expose_outputs: bool = False
) -> WorkflowExtractionOutput:
suggested = None
if output_name is not None:
@@ -877,7 +875,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
return "input_collection"
return "input_dataset"
- def workflow_output_name(content, output_name: Optional[str]) -> Optional[str]:
+ def workflow_output_name(content, output_name: str | None) -> str | None:
if output_name and _skip_output_assoc_name(output_name):
return None
if content.history_content_type == "dataset_collection":
@@ -1020,7 +1018,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
self,
trans: ProvidesHistoryContext,
history_id: DecodedDatabaseIdField,
- force: Optional[bool] = False,
+ force: bool | None = False,
) -> AnyHistoryView:
if trans.anonymous:
raise glx_exceptions.AuthenticationRequired("Only registered users can access archived histories.")
@@ -1035,7 +1033,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
serialization_params: SerializationParams,
filter_query_params: FilterQueryParams,
include_total_matches: bool = False,
- ) -> tuple[list[AnyArchivedHistoryView], Optional[int]]:
+ ) -> tuple[list[AnyArchivedHistoryView], int | None]:
if trans.anonymous:
raise glx_exceptions.AuthenticationRequired("Only registered users can have or access archived histories.")
@@ -1060,7 +1058,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
self,
trans: ProvidesHistoryContext,
history: model.History,
- serialization_params: Optional[SerializationParams] = None,
+ serialization_params: SerializationParams | None = None,
default_view: str = "detailed",
):
if serialization_params is None:
@@ -1070,7 +1068,7 @@ class HistoriesService(ServiceBase, ConsumesModelStores, ServesExportStores):
archived_history["export_record_data"] = export_record_data
return archived_history
- def _get_export_record_data(self, history: model.History) -> Optional[ExportRecordData]:
+ def _get_export_record_data(self, history: model.History) -> ExportRecordData | None:
if history.archive_export_id:
export_record = self.history_export_manager.get_task_export_by_id(history.archive_export_id)
export_metadata = self.history_export_manager.get_record_metadata(export_record)
diff --git a/lib/galaxy/webapps/galaxy/services/history_contents.py b/lib/galaxy/webapps/galaxy/services/history_contents.py
index cc9aa270158..d3e92cd5d09 100644
--- a/lib/galaxy/webapps/galaxy/services/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/services/history_contents.py
@@ -6,9 +6,7 @@ from typing import (
Any,
cast,
Literal,
- Optional,
TYPE_CHECKING,
- Union,
)
from uuid import UUID
@@ -142,25 +140,25 @@ if TYPE_CHECKING:
log = logging.getLogger(__name__)
-DatasetDetailsType = Union[set[DecodedDatabaseIdField], Literal["all"]]
+DatasetDetailsType = set[DecodedDatabaseIdField] | Literal["all"]
class HistoryContentsIndexParams(Model):
"""Query parameters exclusively used by the *new version* of `index` operation."""
- v: Optional[Literal["dev"]]
- dataset_details: Optional[DatasetDetailsType]
+ v: Literal["dev"] | None
+ dataset_details: DatasetDetailsType | None
class LegacyHistoryContentsIndexParams(Model):
"""Query parameters exclusively used by the *legacy version* of `index` operation."""
- ids: Optional[list[DecodedDatabaseIdField]]
+ ids: list[DecodedDatabaseIdField] | None
types: list[HistoryContentType]
- dataset_details: Optional[DatasetDetailsType]
- deleted: Optional[bool]
- visible: Optional[bool]
- shareable: Optional[bool] = Field(
+ dataset_details: DatasetDetailsType | None
+ deleted: bool | None
+ visible: bool | None
+ shareable: bool | None = Field(
default=None,
title="Sharable",
description="Whether to return only shareable or not shareable datasets. Leave unset for both.",
@@ -175,7 +173,7 @@ class HistoryContentsIndexJobsSummaryParams(Model):
class CreateHistoryContentPayloadBase(Model):
- type: Optional[HistoryContentType] = Field(
+ type: HistoryContentType | None = Field(
HistoryContentType.dataset,
title="Type",
description="The type of content to be created in the history.",
@@ -183,12 +181,12 @@ class CreateHistoryContentPayloadBase(Model):
class CreateHistoryContentPayloadFromCopy(CreateHistoryContentPayloadBase):
- source: Optional[HistoryContentSource] = Field(
+ source: HistoryContentSource | None = Field(
None,
title="Source",
description="The source of the content. Can be other history element to be copied or library elements.",
)
- content: Optional[Union[DecodedDatabaseIdField, LibraryFolderDatabaseIdField]] = Field(
+ content: DecodedDatabaseIdField | LibraryFolderDatabaseIdField | None = Field(
None,
title="Content",
description=(
@@ -202,7 +200,7 @@ class CreateHistoryContentPayloadFromCopy(CreateHistoryContentPayloadBase):
class CollectionElementIdentifier(Model):
- name: Optional[str] = Field(
+ name: str | None = Field(
None,
title="Name",
description="The name of the element.",
@@ -212,7 +210,7 @@ class CollectionElementIdentifier(Model):
title="Source",
description="The source of the element.",
)
- id: Optional[DecodedDatabaseIdField] = Field(
+ id: DecodedDatabaseIdField | None = Field(
None,
title="ID",
description="The encoded ID of the element.",
@@ -222,12 +220,12 @@ class CollectionElementIdentifier(Model):
title="Tags",
description="The list of tags associated with the element.",
)
- element_identifiers: Optional[list["CollectionElementIdentifier"]] = Field(
+ element_identifiers: list["CollectionElementIdentifier"] | None = Field(
default=None,
title="Element Identifiers",
description="List of elements that should be in the new nested collection.",
)
- collection_type: Optional[str] = Field(
+ collection_type: str | None = Field(
default=None,
title="Collection Type",
description="The type of the nested collection. For example, `list`, `paired`, `list:paired`.",
@@ -244,12 +242,12 @@ class CreateHistoryContentFromStore(StoreContentSource):
class CreateHistoryContentPayloadFromCollection(CreateHistoryContentPayloadFromCopy):
- dbkey: Optional[str] = Field(
+ dbkey: str | None = Field(
default=None,
title="DBKey",
description="TODO",
)
- copy_elements: Optional[bool] = Field(
+ copy_elements: bool | None = Field(
default=True,
title="Copy Elements",
description=(
@@ -322,7 +320,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
serialization_params: SerializationParams,
filter_query_params: FilterQueryParams,
accept: str,
- ) -> Union[HistoryContentsResult, HistoryContentsWithStatsResult]:
+ ) -> HistoryContentsResult | HistoryContentsWithStatsResult:
"""
Return a list of contents (HDAs and HDCAs) for the history with the given ``ID``.
@@ -338,7 +336,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
id: DecodedDatabaseIdField,
serialization_params: SerializationParams,
contents_type: HistoryContentType,
- fuzzy_count: Optional[int] = None,
+ fuzzy_count: int | None = None,
) -> AnyHistoryContentItem:
"""
Return detailed information about an HDA or HDCA within a history
@@ -530,7 +528,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
history_id: DecodedDatabaseIdField,
payload: CreateHistoryContentPayload,
serialization_params: SerializationParams,
- ) -> Union[AnyHistoryContentItem, list[AnyHistoryContentItem]]:
+ ) -> AnyHistoryContentItem | list[AnyHistoryContentItem]:
"""
Create a new HDA or HDCA.
@@ -645,7 +643,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
def update(
self,
trans,
- history_id: Optional[DecodedDatabaseIdField],
+ history_id: DecodedDatabaseIdField | None,
id: DecodedDatabaseIdField,
payload: dict[str, Any],
serialization_params: SerializationParams,
@@ -835,7 +833,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
run_id: DecodedDatabaseIdField,
offset: int = 0,
limit: int = 50,
- search: Optional[str] = None,
+ search: str | None = None,
) -> tuple[list[StorageOperationRunItemStatus], int]:
user = self.get_authenticated_user(trans)
history = self.history_manager.get_mutable(history_id, user, current_history=trans.history)
@@ -897,9 +895,9 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
trans,
history_id: DecodedDatabaseIdField,
filter_query_params: FilterQueryParams,
- filename: Optional[str] = "",
- dry_run: Optional[bool] = True,
- ) -> Union[HistoryContentsArchiveDryRunResult, ZipstreamWrapper]:
+ filename: str | None = "",
+ dry_run: bool | None = True,
+ ) -> HistoryContentsArchiveDryRunResult | ZipstreamWrapper:
"""
Build and return a compressed archive of the selected history contents
@@ -1100,7 +1098,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
serialization_params: SerializationParams,
filter_query_params: FilterQueryParams,
accept: str,
- ) -> Union[HistoryContentsResult, HistoryContentsWithStatsResult]:
+ ) -> HistoryContentsResult | HistoryContentsWithStatsResult:
"""
Latests implementation of the `index` action.
Allows additional filtering of contents and custom serialization.
@@ -1160,7 +1158,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
self,
trans,
content,
- dataset_details: Optional[DatasetDetailsType] = None,
+ dataset_details: DatasetDetailsType | None = None,
):
encoded_content_id = content.id
detailed = dataset_details and (dataset_details == "all" or (encoded_content_id in dataset_details))
@@ -1177,7 +1175,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
self,
trans,
content,
- dataset_details: Optional[DatasetDetailsType],
+ dataset_details: DatasetDetailsType | None,
serialization_params: SerializationParams,
default_view: str = "summary",
):
@@ -1188,7 +1186,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
serialization_params_dict = serialization_params.model_dump()
view = serialization_params_dict.pop("view", default_view) or default_view
- serializer: Optional[ModelSerializer] = None
+ serializer: ModelSerializer | None = None
if isinstance(content, HistoryDatasetAssociation):
serializer = self.hda_serializer
if dataset_details and (dataset_details == "all" or content.id in dataset_details):
@@ -1250,7 +1248,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
trans,
id: DecodedDatabaseIdField,
serialization_params: SerializationParams,
- fuzzy_count: Optional[int] = None,
+ fuzzy_count: int | None = None,
):
dataset_collection_instance = self.__get_accessible_collection(trans, id)
view = serialization_params.view or "element"
@@ -1473,7 +1471,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
self,
contents: Iterable["HistoryItem"],
operation: HistoryContentItemOperation,
- params: Optional[AnyBulkOperationParams],
+ params: AnyBulkOperationParams | None,
trans: ProvidesHistoryContext,
) -> list[BulkOperationItemError]:
errors: list[BulkOperationItemError] = []
@@ -1487,9 +1485,9 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
self,
operation: HistoryContentItemOperation,
item: "HistoryItem",
- params: Optional[AnyBulkOperationParams],
+ params: AnyBulkOperationParams | None,
trans: ProvidesHistoryContext,
- ) -> Optional[BulkOperationItemError]:
+ ) -> BulkOperationItemError | None:
try:
self.item_operator.apply(operation, item, params, trans)
return None
@@ -1523,7 +1521,7 @@ class HistoriesContentsService(ServiceBase, ServesExportStores, ConsumesModelSto
class ItemOperation(Protocol):
def __call__(
- self, item: "HistoryItem", params: Optional[AnyBulkOperationParams], trans: ProvidesHistoryContext
+ self, item: "HistoryItem", params: AnyBulkOperationParams | None, trans: ProvidesHistoryContext
) -> None: ...
@@ -1558,7 +1556,7 @@ class HistoryItemOperator:
self,
operation: HistoryContentItemOperation,
item: "HistoryItem",
- params: Optional[AnyBulkOperationParams],
+ params: AnyBulkOperationParams | None,
trans: ProvidesHistoryContext,
):
self._operation_map[operation](item, params, trans)
diff --git a/lib/galaxy/webapps/galaxy/services/jobs.py b/lib/galaxy/webapps/galaxy/services/jobs.py
index 2ae4eb47e6c..b7d98a9cae9 100644
--- a/lib/galaxy/webapps/galaxy/services/jobs.py
+++ b/lib/galaxy/webapps/galaxy/services/jobs.py
@@ -2,9 +2,7 @@ import logging
from enum import Enum
from typing import (
Any,
- Optional,
TYPE_CHECKING,
- Union,
)
from pydantic import (
@@ -75,25 +73,25 @@ log = logging.getLogger(__name__)
class JobRequest(BaseModel):
- tool_id: Optional[str] = Field(default=None, title="tool_id", description="TODO")
- tool_uuid: Optional[str] = Field(default=None, title="tool_uuid", description="TODO")
- tool_version: Optional[str] = Field(default=None, title="tool_version", description="TODO")
- history_id: Optional[DecodedDatabaseIdField] = Field(default=None, title="history_id", description="TODO")
- inputs: Optional[dict[str, Any]] = Field(default_factory=lambda: {}, title="Inputs", description="TODO")
+ tool_id: str | None = Field(default=None, title="tool_id", description="TODO")
+ tool_uuid: str | None = Field(default=None, title="tool_uuid", description="TODO")
+ tool_version: str | None = Field(default=None, title="tool_version", description="TODO")
+ history_id: DecodedDatabaseIdField | None = Field(default=None, title="history_id", description="TODO")
+ inputs: dict[str, Any] | None = Field(default_factory=lambda: {}, title="Inputs", description="TODO")
strict: bool = Field(
default=True,
title="Strict",
description="Turn on strict validation of the inputs that drops support for some inconsistent legacy behavior.",
)
- use_cached_jobs: Optional[bool] = Field(default=None, title="use_cached_jobs")
- rerun_remap_job_id: Optional[DecodedDatabaseIdField] = Field(
+ use_cached_jobs: bool | None = Field(default=None, title="use_cached_jobs")
+ rerun_remap_job_id: DecodedDatabaseIdField | None = Field(
default=None, title="rerun_remap_job_id", description="TODO"
)
send_email_notification: bool = Field(default=False, title="Send Email Notification", description="TODO")
- preferred_object_store_id: Optional[str] = Field(default=None, title="Preferred Object Store ID")
- tags: Optional[list[str]] = Field(default=None, title="Tags")
- data_manager_mode: Optional[str] = Field(default=None, title="Data Manager Mode")
- credentials_context: Optional[list[dict[str, Any]]] = Field(default=None, title="Credentials Context")
+ preferred_object_store_id: str | None = Field(default=None, title="Preferred Object Store ID")
+ tags: list[str] | None = Field(default=None, title="Tags")
+ data_manager_mode: str | None = Field(default=None, title="Data Manager Mode")
+ credentials_context: list[dict[str, Any]] | None = Field(default=None, title="Credentials Context")
class JobCreateResponse(BaseModel):
@@ -181,8 +179,8 @@ class JobsService(ServiceBase):
self,
view: JobIndexViewEnum,
user_details: bool,
- decoded_user_id: Optional[DecodedDatabaseIdField],
- trans_user_id: Optional[int],
+ decoded_user_id: DecodedDatabaseIdField | None,
+ trans_user_id: int | None,
):
"""Verify admin-only resources are not being accessed."""
if view == JobIndexViewEnum.admin_job_list:
@@ -195,8 +193,8 @@ class JobsService(ServiceBase):
def get_job(
self,
trans: ProvidesUserContext,
- job_id: Optional[int] = None,
- dataset_id: Optional[int] = None,
+ job_id: int | None = None,
+ dataset_id: int | None = None,
hda_ldda: str = "hda",
) -> Job:
if job_id is not None:
@@ -204,7 +202,7 @@ class JobsService(ServiceBase):
elif dataset_id is not None:
# Following checks dataset accessible
if hda_ldda == "hda":
- dataset_instance: Union[HistoryDatasetAssociation, LibraryDatasetDatasetAssociation] = (
+ dataset_instance: HistoryDatasetAssociation | LibraryDatasetDatasetAssociation = (
self.hda_manager.get_accessible(id=dataset_id, user=trans.user)
)
else:
diff --git a/lib/galaxy/webapps/galaxy/services/libraries.py b/lib/galaxy/webapps/galaxy/services/libraries.py
index e7dfd0aa050..0b280fefa05 100644
--- a/lib/galaxy/webapps/galaxy/services/libraries.py
+++ b/lib/galaxy/webapps/galaxy/services/libraries.py
@@ -1,8 +1,6 @@
import logging
from typing import (
Any,
- Optional,
- Union,
)
from galaxy import (
@@ -60,7 +58,7 @@ class LibrariesService(ServiceBase, ConsumesModelStores):
self.library_manager = library_manager
self.role_manager = role_manager
- def index(self, trans: ProvidesAppContext, deleted: Optional[bool] = False) -> LibrarySummaryList:
+ def index(self, trans: ProvidesAppContext, deleted: bool | None = False) -> LibrarySummaryList:
"""Returns a list of summary data for all libraries.
:param deleted: if True, show only ``deleted`` libraries, if False show only ``non-deleted``
@@ -114,7 +112,7 @@ class LibrariesService(ServiceBase, ConsumesModelStores):
updated_library = self.library_manager.update(trans, library, name, payload.description, payload.synopsis)
return self._to_summary(trans, updated_library)
- def delete(self, trans, id: DecodedDatabaseIdField, undelete: Optional[bool] = False) -> LibrarySummary:
+ def delete(self, trans, id: DecodedDatabaseIdField, undelete: bool | None = False) -> LibrarySummary:
"""Marks the library with the given ``id`` as `deleted` (or removes the `deleted` mark if the `undelete` param is true)
.. note:: Currently, only admin users can un/delete libraries.
@@ -132,12 +130,12 @@ class LibrariesService(ServiceBase, ConsumesModelStores):
self,
trans,
id: DecodedDatabaseIdField,
- scope: Optional[LibraryPermissionScope] = LibraryPermissionScope.current,
- is_library_access: Optional[bool] = False,
+ scope: LibraryPermissionScope | None = LibraryPermissionScope.current,
+ is_library_access: bool | None = False,
page: int = 1,
page_limit: int = 10,
- query: Optional[str] = None,
- ) -> Union[LibraryCurrentPermissions, LibraryAvailablePermissions]:
+ query: str | None = None,
+ ) -> LibraryCurrentPermissions | LibraryAvailablePermissions:
"""Load all permissions for the given library id and return it.
:param id: the encoded id of the library
@@ -188,7 +186,7 @@ class LibrariesService(ServiceBase, ConsumesModelStores):
def set_permissions(
self, trans, id: DecodedDatabaseIdField, payload: dict[str, Any]
- ) -> Union[LibraryLegacySummary, LibraryCurrentPermissions]: # Old legacy response
+ ) -> LibraryLegacySummary | LibraryCurrentPermissions: # Old legacy response
"""Set permissions of the given library to the given role ids.
:param id: the encoded id of the library to set the permissions of
diff --git a/lib/galaxy/webapps/galaxy/services/library_contents.py b/lib/galaxy/webapps/galaxy/services/library_contents.py
index 0c17a6eb463..9283004215e 100644
--- a/lib/galaxy/webapps/galaxy/services/library_contents.py
+++ b/lib/galaxy/webapps/galaxy/services/library_contents.py
@@ -4,8 +4,6 @@ import tempfile
from typing import (
Annotated,
cast,
- Optional,
- Union,
)
from fastapi import Path
@@ -85,7 +83,7 @@ class LibraryContentsService(ServiceBase, LibraryActions, UsesLibraryMixinItems,
library_id: DecodedDatabaseIdField,
) -> LibraryContentsIndexListResponse:
"""Return a list of library files and folders."""
- rval: list[Union[LibraryContentsIndexFolderResponse, LibraryContentsIndexDatasetResponse]] = []
+ rval: list[LibraryContentsIndexFolderResponse | LibraryContentsIndexDatasetResponse] = []
current_user_roles = trans.get_current_user_roles()
library = trans.sa_session.get(Library, library_id)
if not library:
@@ -99,7 +97,7 @@ class LibraryContentsService(ServiceBase, LibraryActions, UsesLibraryMixinItems,
# appending all other items in the library recursively
for content in self._traverse(trans, library.root_folder, current_user_roles):
url = self._url_for(trans, library_id, content.id, content.api_type)
- response_model: Union[LibraryContentsIndexFolderResponse, LibraryContentsIndexDatasetResponse]
+ response_model: LibraryContentsIndexFolderResponse | LibraryContentsIndexDatasetResponse
common_args = dict(id=content.id, type=content.api_type, name=content.api_path, url=url)
if content.api_type == "folder":
response_model = LibraryContentsIndexFolderResponse(**common_args)
@@ -130,7 +128,7 @@ class LibraryContentsService(ServiceBase, LibraryActions, UsesLibraryMixinItems,
trans: ProvidesHistoryContext,
library_id: DecodedDatabaseIdField,
payload: AnyLibraryContentsCreatePayload,
- files: Optional[list[StarletteUploadFile]] = None,
+ files: list[StarletteUploadFile] | None = None,
) -> AnyLibraryContentsCreateResponse:
"""Create a new library file or folder."""
if trans.user_is_bootstrap_admin:
diff --git a/lib/galaxy/webapps/galaxy/services/library_folders.py b/lib/galaxy/webapps/galaxy/services/library_folders.py
index be24e0e81b2..2c0e27814bb 100644
--- a/lib/galaxy/webapps/galaxy/services/library_folders.py
+++ b/lib/galaxy/webapps/galaxy/services/library_folders.py
@@ -1,8 +1,4 @@
import logging
-from typing import (
- Optional,
- Union,
-)
from galaxy import util
from galaxy.exceptions import (
@@ -82,11 +78,11 @@ class LibraryFoldersService(ServiceBase):
self,
trans,
folder_id: LibraryFolderDatabaseIdField,
- scope: Optional[LibraryPermissionScope] = LibraryPermissionScope.current,
+ scope: LibraryPermissionScope | None = LibraryPermissionScope.current,
page: int = 1,
page_limit: int = 10,
- query: Optional[str] = None,
- ) -> Union[LibraryFolderCurrentPermissions, LibraryAvailablePermissions]:
+ query: str | None = None,
+ ) -> LibraryFolderCurrentPermissions | LibraryAvailablePermissions:
"""
Load all permissions for the given folder id and return it.
@@ -229,7 +225,7 @@ class LibraryFoldersService(ServiceBase):
return LibraryFolderCurrentPermissions(**current_permissions)
def delete(
- self, trans, folder_id: LibraryFolderDatabaseIdField, undelete: Optional[bool] = False
+ self, trans, folder_id: LibraryFolderDatabaseIdField, undelete: bool | None = False
) -> LibraryFolderDetails:
"""
Mark the folder with the given ``encoded_folder_id`` as `deleted`
diff --git a/lib/galaxy/webapps/galaxy/services/notifications.py b/lib/galaxy/webapps/galaxy/services/notifications.py
index 7fd4cd696a5..ad1b03e9497 100644
--- a/lib/galaxy/webapps/galaxy/services/notifications.py
+++ b/lib/galaxy/webapps/galaxy/services/notifications.py
@@ -1,8 +1,6 @@
from datetime import datetime
from typing import (
NoReturn,
- Optional,
- Union,
)
from galaxy.exceptions import (
@@ -54,7 +52,7 @@ class NotificationService(ServiceBase):
def send_internal_notification(
self, request: NotificationCreateRequest, force_sync: bool = False
- ) -> Union[NotificationCreatedResponse, AsyncTaskResultSummary]:
+ ) -> NotificationCreatedResponse | AsyncTaskResultSummary:
"""Send a system-emitted notification on behalf of internal callers (e.g. share flows).
Unlike :meth:`send_notification`, this skips admin/permission checks because the
@@ -64,7 +62,7 @@ class NotificationService(ServiceBase):
def send_notification(
self, sender_context: ProvidesUserContext, payload: NotificationCreateRequestBody
- ) -> Union[NotificationCreatedResponse, AsyncTaskResultSummary]:
+ ) -> NotificationCreatedResponse | AsyncTaskResultSummary:
"""Sends a notification to a list of recipients (users, groups or roles).
Before sending the notification, it checks if the requesting user has the necessary permissions to do so.
@@ -95,9 +93,7 @@ class NotificationService(ServiceBase):
total_notifications_sent=1, notification=NotificationResponse.model_validate(notification)
)
- def build_status_catchup(
- self, user_context: ProvidesUserContext, last_event_id: Optional[str]
- ) -> Optional[SSEEvent]:
+ def build_status_catchup(self, user_context: ProvidesUserContext, last_event_id: str | None) -> SSEEvent | None:
"""Build a ``notification_status`` SSE event covering everything since ``last_event_id``.
Returns ``None`` when catch-up isn't possible (no ``Last-Event-ID``,
@@ -135,7 +131,7 @@ class NotificationService(ServiceBase):
)
def get_user_notifications(
- self, user_context: ProvidesUserContext, limit: Optional[int] = None, offset: Optional[int] = None
+ self, user_context: ProvidesUserContext, limit: int | None = None, offset: int | None = None
) -> UserNotificationListResponse:
"""Returns all the notifications received by the user that haven't expired yet..
@@ -256,7 +252,7 @@ class NotificationService(ServiceBase):
raise RequestParameterInvalidException("Please specify at least one value to update for notifications.")
def _get_all_broadcasted(
- self, since: Optional[datetime] = None, active_only: Optional[bool] = True
+ self, since: datetime | None = None, active_only: bool | None = True
) -> list[BroadcastNotificationResponse]:
notifications = self.notification_manager.get_all_broadcasted_notifications(since, active_only)
broadcasted_notifications = [
@@ -267,9 +263,9 @@ class NotificationService(ServiceBase):
def _get_user_notifications(
self,
user_context: ProvidesUserContext,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- since: Optional[datetime] = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ since: datetime | None = None,
) -> list[UserNotificationResponse]:
notifications = self.notification_manager.get_user_notifications(user_context.user, limit, offset, since)
user_notifications = [UserNotificationResponse.model_validate(notification) for notification in notifications]
diff --git a/lib/galaxy/webapps/galaxy/services/pages.py b/lib/galaxy/webapps/galaxy/services/pages.py
index 559e05bc0e0..beaae1b27e1 100644
--- a/lib/galaxy/webapps/galaxy/services/pages.py
+++ b/lib/galaxy/webapps/galaxy/services/pages.py
@@ -1,7 +1,4 @@
import logging
-from typing import (
- Union,
-)
from galaxy import exceptions
from galaxy.celery.helpers import async_task_summary
@@ -69,7 +66,7 @@ class PagesService(ServiceBase):
def index(
self, trans, payload: PageIndexQueryPayload, include_total_count: bool = False
- ) -> tuple[PageSummaryList, Union[int, None]]:
+ ) -> tuple[PageSummaryList, int | None]:
"""Return a list of Pages viewable by the user
:rtype: list
diff --git a/lib/galaxy/webapps/galaxy/services/quotas.py b/lib/galaxy/webapps/galaxy/services/quotas.py
index c45f7742c7c..29c538a7d01 100644
--- a/lib/galaxy/webapps/galaxy/services/quotas.py
+++ b/lib/galaxy/webapps/galaxy/services/quotas.py
@@ -1,5 +1,4 @@
import logging
-from typing import Optional
from sqlalchemy import (
false,
@@ -101,7 +100,7 @@ class QuotasService(ServiceBase):
return "; ".join(messages)
def delete(
- self, trans: ProvidesUserContext, id: DecodedDatabaseIdField, payload: Optional[DeleteQuotaPayload] = None
+ self, trans: ProvidesUserContext, id: DecodedDatabaseIdField, payload: DeleteQuotaPayload | None = None
) -> str:
"""Marks a quota as deleted."""
quota = self.quota_manager.get_quota(
diff --git a/lib/galaxy/webapps/galaxy/services/roles.py b/lib/galaxy/webapps/galaxy/services/roles.py
index 93bba884fbc..35c0fdfb86b 100644
--- a/lib/galaxy/webapps/galaxy/services/roles.py
+++ b/lib/galaxy/webapps/galaxy/services/roles.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from galaxy.managers.context import ProvidesUserContext
from galaxy.managers.roles import RoleManager
from galaxy.model.db.role import get_private_role_user_emails_dict
@@ -17,7 +15,7 @@ from galaxy.webapps.base.controller import url_for
from galaxy.webapps.galaxy.services.base import ServiceBase
-def role_to_model(role, displayed_name: Optional[str] = None):
+def role_to_model(role, displayed_name: str | None = None):
item = role.to_dict(view="element")
role_id = Security.security.encode_id(role.id)
item["url"] = url_for("role", id=role_id)
@@ -29,7 +27,6 @@ def role_to_model(role, displayed_name: Optional[str] = None):
class RolesService(ServiceBase):
-
def __init__(
self,
security: IdEncodingHelper,
@@ -41,9 +38,9 @@ class RolesService(ServiceBase):
def get_index(
self,
trans: ProvidesUserContext,
- search: Optional[str] = None,
- limit: Optional[int] = None,
- offset: Optional[int] = 0,
+ search: str | None = None,
+ limit: int | None = None,
+ offset: int | None = 0,
) -> RoleListResponse:
roles = self.role_manager.list_displayable_roles(trans, search=search, limit=limit, offset=offset or 0)
role_ids = {r.id for r in roles}
diff --git a/lib/galaxy/webapps/galaxy/services/sharable.py b/lib/galaxy/webapps/galaxy/services/sharable.py
index eec9fb1e257..9a6144049d1 100644
--- a/lib/galaxy/webapps/galaxy/services/sharable.py
+++ b/lib/galaxy/webapps/galaxy/services/sharable.py
@@ -1,8 +1,4 @@
import logging
-from typing import (
- Optional,
- Union,
-)
from galaxy.managers import base
from galaxy.managers.sharable import (
@@ -38,12 +34,7 @@ from galaxy.webapps.galaxy.services.notifications import NotificationService
log = logging.getLogger(__name__)
-SharableItem = Union[
- History,
- StoredWorkflow,
- Visualization,
- Page,
-]
+SharableItem = History | StoredWorkflow | Visualization | Page
class ShareableService:
@@ -124,7 +115,7 @@ class ShareableService:
item,
users: set[User],
errors: set[str],
- share_option: Optional[SharingOptions] = None,
+ share_option: SharingOptions | None = None,
):
new_users = None
extra = self.manager.get_sharing_extra_information(trans, item, users, errors, share_option)
@@ -175,7 +166,7 @@ class ShareableService:
return send_to_users, send_to_err
def _send_notification_to_users(
- self, users_to_notify: set[User], item: SharableItem, status: ShareWithStatus, galaxy_url: Optional[str] = None
+ self, users_to_notify: set[User], item: SharableItem, status: ShareWithStatus, galaxy_url: str | None = None
):
if self.notification_service.notifications_enabled and not status.errors and users_to_notify:
request = SharedItemNotificationFactory.build_notification_request(
@@ -198,7 +189,7 @@ class SharedItemNotificationFactory:
@staticmethod
def build_notification_request(
- item: SharableItem, users_to_notify: set[User], status: ShareWithStatus, galaxy_url: Optional[str] = None
+ item: SharableItem, users_to_notify: set[User], status: ShareWithStatus, galaxy_url: str | None = None
) -> NotificationCreateRequest:
user_ids = [user.id for user in users_to_notify]
request = NotificationCreateRequest(
diff --git a/lib/galaxy/webapps/galaxy/services/storage_cleaner.py b/lib/galaxy/webapps/galaxy/services/storage_cleaner.py
index a9c79f2ba10..5ff7ed7e068 100644
--- a/lib/galaxy/webapps/galaxy/services/storage_cleaner.py
+++ b/lib/galaxy/webapps/galaxy/services/storage_cleaner.py
@@ -1,7 +1,4 @@
import logging
-from typing import (
- Optional,
-)
from galaxy.managers.base import StorageCleanerManager
from galaxy.managers.context import ProvidesHistoryContext
@@ -42,9 +39,9 @@ class StorageCleanerService(ServiceBase):
self,
trans: ProvidesHistoryContext,
stored_item_type: StoredItemType,
- offset: Optional[int] = None,
- limit: Optional[int] = None,
- order: Optional[StoredItemOrderBy] = None,
+ offset: int | None = None,
+ limit: int | None = None,
+ order: StoredItemOrderBy | None = None,
):
user = self.get_authenticated_user(trans)
return self.storage_cleaner_map[stored_item_type].get_discarded(user, offset, limit, order)
@@ -57,9 +54,9 @@ class StorageCleanerService(ServiceBase):
self,
trans: ProvidesHistoryContext,
stored_item_type: StoredItemType,
- offset: Optional[int] = None,
- limit: Optional[int] = None,
- order: Optional[StoredItemOrderBy] = None,
+ offset: int | None = None,
+ limit: int | None = None,
+ order: StoredItemOrderBy | None = None,
):
user = self.get_authenticated_user(trans)
return self.storage_cleaner_map[stored_item_type].get_archived(user, offset, limit, order)
diff --git a/lib/galaxy/webapps/galaxy/services/tool_shed_repositories.py b/lib/galaxy/webapps/galaxy/services/tool_shed_repositories.py
index 6f2be4ed2b3..84186ab087e 100644
--- a/lib/galaxy/webapps/galaxy/services/tool_shed_repositories.py
+++ b/lib/galaxy/webapps/galaxy/services/tool_shed_repositories.py
@@ -1,7 +1,3 @@
-from typing import (
- Optional,
-)
-
from pydantic import BaseModel
from sqlalchemy import (
cast,
@@ -25,11 +21,11 @@ from galaxy.web import url_for
class InstalledToolShedRepositoryIndexRequest(BaseModel):
- name: Optional[str] = None
- owner: Optional[str] = None
- changeset: Optional[str] = None
- deleted: Optional[bool] = None
- uninstalled: Optional[bool] = None
+ name: str | None = None
+ owner: str | None = None
+ changeset: str | None = None
+ deleted: bool | None = None
+ uninstalled: bool | None = None
class ToolShedRepositoriesService:
@@ -59,7 +55,7 @@ class ToolShedRepositoriesService:
assert tool_shed_repository
return self._show(tool_shed_repository)
- def check_for_updates(self, repository_id: Optional[int]) -> CheckForUpdatesResponse:
+ def check_for_updates(self, repository_id: int | None) -> CheckForUpdatesResponse:
message, status = check_for_updates(self._tool_shed_registry, self._install_model_context, repository_id)
return CheckForUpdatesResponse(message=message, status=status)
diff --git a/lib/galaxy/webapps/galaxy/services/tools.py b/lib/galaxy/webapps/galaxy/services/tools.py
index da421f524f7..4e3b72ac2ee 100644
--- a/lib/galaxy/webapps/galaxy/services/tools.py
+++ b/lib/galaxy/webapps/galaxy/services/tools.py
@@ -7,8 +7,6 @@ from typing import (
Any,
cast,
get_args,
- Optional,
- Union,
)
from uuid import UUID
@@ -74,7 +72,7 @@ JobCreateResponse = dict[str, Any]
def get_tool(trans: ProvidesHistoryContext, tool_ref: ToolRunReference) -> Tool:
- tool: Optional[Tool] = None
+ tool: Tool | None = None
if tool_ref.tool_uuid and trans.user:
tool = trans.app.toolbox.get_unprivileged_tool_or_none(trans.user, tool_uuid=tool_ref.tool_uuid)
if not tool:
@@ -121,7 +119,7 @@ def file_landing_payload_to_fetch_targets(data_landing_payload: CreateFileLandin
f"Sample sheet metadata (column_definitions, rows) can only be used with collection_type 'sample_sheet' or 'sample_sheet:', not '{collection_type}'"
)
- targets: list[Union[DataElementsTarget, HdcaDataItemsTarget]] = []
+ targets: list[DataElementsTarget | HdcaDataItemsTarget] = []
for request_item in data_landing_payload.request_state:
if isinstance(request_item, (DataRequestUri, FileRequestUri)):
@@ -279,8 +277,8 @@ class ToolsService(ServiceBase):
def create_fetch(
self,
trans: ProvidesHistoryContext,
- fetch_payload: Union[FetchDataFormPayload, FetchDataPayload],
- files: Optional[list[UploadFile]] = None,
+ fetch_payload: FetchDataFormPayload | FetchDataPayload,
+ files: list[UploadFile] | None = None,
) -> JobCreateResponse:
payload = fetch_payload.model_dump(exclude_unset=True)
request_version = "1"
@@ -454,7 +452,7 @@ class ToolsService(ServiceBase):
trans.security.encode_all_ids(rval, recursive=True)
return rval
- def _search(self, q: str, view: Optional[str]) -> list[str]:
+ def _search(self, q: str, view: str | None) -> list[str]:
"""
Perform the search on the given query.
Boosts and numer of results are configurable in galaxy.ini file.
@@ -503,7 +501,7 @@ class ToolsService(ServiceBase):
# -- Helper methods --
#
def _get_tool(
- self, trans: ProvidesUserContext, id, tool_version=None, tool_uuid=None, user: Optional[User] = None
+ self, trans: ProvidesUserContext, id, tool_version=None, tool_uuid=None, user: User | None = None
) -> Tool:
if tool_uuid:
try:
@@ -539,7 +537,7 @@ class ToolsService(ServiceBase):
detected_versions.append(tool.version)
return detected_versions
- def get_tool_icon_path(self, trans, tool_id, tool_version=None) -> Optional[str]:
+ def get_tool_icon_path(self, trans, tool_id, tool_version=None) -> str | None:
tool = self._get_tool(trans, tool_id, tool_version)
if tool and tool.icon:
icon_file_path = tool.icon
diff --git a/lib/galaxy/webapps/galaxy/services/users.py b/lib/galaxy/webapps/galaxy/services/users.py
index dd8fa7650c1..a32743b99a3 100644
--- a/lib/galaxy/webapps/galaxy/services/users.py
+++ b/lib/galaxy/webapps/galaxy/services/users.py
@@ -1,7 +1,5 @@
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
)
import galaxy.managers.base as managers_base
@@ -87,7 +85,7 @@ class UsersService(ServiceBase):
)
return None
- def get_api_key(self, trans: ProvidesUserContext, user_id: int) -> Optional[APIKeyModel]:
+ def get_api_key(self, trans: ProvidesUserContext, user_id: int) -> APIKeyModel | None:
"""Returns the current API key or None if the user doesn't have any valid API key."""
user = self.get_user(trans, user_id)
api_key = self.api_key_manager.get_api_key(user)
@@ -120,8 +118,8 @@ class UsersService(ServiceBase):
def _anon_user_api_value(self, trans: ProvidesHistoryContext):
"""Return data for an anonymous user, truncated to only usage and quota_percent"""
if not trans.user and not trans.history:
- usage: Optional[float] = 0.0
- percent: Optional[int] = 0
+ usage: float | None = 0.0
+ percent: int | None = 0
else:
usage = self.quota_agent.get_usage(trans, history=trans.history)
percent = self.quota_agent.get_percent(trans=trans, usage=usage)
@@ -148,7 +146,7 @@ class UsersService(ServiceBase):
trans: ProvidesUserContext,
user_id: FlexibleUserIdType,
deleted: bool,
- ) -> Optional[User]:
+ ) -> User | None:
try:
# user is requesting data about themselves
if user_id == "current":
@@ -181,7 +179,7 @@ class UsersService(ServiceBase):
trans: ProvidesHistoryContext,
user_id: FlexibleUserIdType,
deleted: bool,
- ) -> Union[DetailedUserModel, AnonUserModel]:
+ ) -> DetailedUserModel | AnonUserModel:
user = self.get_user_full(trans=trans, deleted=deleted, user_id=user_id)
if user is not None:
return self.user_to_detailed_model(user)
@@ -199,11 +197,11 @@ class UsersService(ServiceBase):
self,
trans: ProvidesUserContext,
deleted: bool,
- f_email: Optional[str],
- f_name: Optional[str],
- f_any: Optional[str],
- limit: Optional[int] = None,
- offset: Optional[int] = 0,
+ f_email: str | None,
+ f_name: str | None,
+ f_any: str | None,
+ limit: int | None = None,
+ offset: int | None = 0,
) -> list[MaybeLimitedUserModel]:
# never give any info to non-authenticated users
if not trans.user and not trans.user_is_bootstrap_admin:
diff --git a/lib/galaxy/webapps/galaxy/services/visualizations.py b/lib/galaxy/webapps/galaxy/services/visualizations.py
index 9eec6478f09..076fe2697f4 100644
--- a/lib/galaxy/webapps/galaxy/services/visualizations.py
+++ b/lib/galaxy/webapps/galaxy/services/visualizations.py
@@ -2,8 +2,6 @@ import json
import logging
from typing import (
cast,
- Optional,
- Union,
)
from galaxy import exceptions
@@ -75,7 +73,7 @@ class VisualizationsService(ServiceBase):
trans: ProvidesUserContext,
payload: VisualizationIndexQueryPayload,
include_total_count: bool = False,
- ) -> tuple[VisualizationSummaryList, Union[int, None]]:
+ ) -> tuple[VisualizationSummaryList, int | None]:
"""Return a list of Visualizations viewable by the user
:rtype: list
@@ -145,7 +143,7 @@ class VisualizationsService(ServiceBase):
def create(
self,
trans: ProvidesUserContext,
- import_id: Optional[DecodedDatabaseIdField],
+ import_id: DecodedDatabaseIdField | None,
payload: VisualizationCreatePayload,
) -> VisualizationCreateResponse:
"""Returns a dictionary of the created visualization
@@ -182,7 +180,7 @@ class VisualizationsService(ServiceBase):
trans: ProvidesUserContext,
visualization_id: DecodedDatabaseIdField,
payload: VisualizationUpdatePayload,
- ) -> Optional[VisualizationUpdateResponse]:
+ ) -> VisualizationUpdateResponse | None:
"""
Update a visualization
@@ -260,9 +258,9 @@ class VisualizationsService(ServiceBase):
self,
trans: ProvidesUserContext,
visualization: Visualization,
- config: Optional[Union[dict, bytes]],
- title: Optional[str],
- dbkey: Optional[str],
+ config: dict | bytes | None,
+ title: str | None,
+ dbkey: str | None,
) -> VisualizationRevision:
"""
Adds a new `VisualizationRevision` to the given `visualization` with
@@ -283,10 +281,10 @@ class VisualizationsService(ServiceBase):
self,
trans: ProvidesUserContext,
type: str,
- title: Optional[str] = "Untitled Visualization",
- dbkey: Optional[str] = None,
- slug: Optional[str] = None,
- annotation: Optional[str] = None,
+ title: str | None = "Untitled Visualization",
+ dbkey: str | None = None,
+ slug: str | None = None,
+ annotation: str | None = None,
) -> Visualization:
"""Create visualization but not first revision. Returns Visualization object."""
user = trans.get_user()
diff --git a/lib/galaxy/webapps/galaxy/services/wes.py b/lib/galaxy/webapps/galaxy/services/wes.py
index 16918f910e9..80d68b87683 100644
--- a/lib/galaxy/webapps/galaxy/services/wes.py
+++ b/lib/galaxy/webapps/galaxy/services/wes.py
@@ -5,7 +5,6 @@ import logging
from dataclasses import dataclass
from typing import (
Any,
- Optional,
)
from urllib.parse import (
parse_qs,
@@ -154,8 +153,8 @@ def _parse_gxworkflow_uri(workflow_url: str) -> tuple[str, bool]:
def _load_workflow_content(
trans: ProvidesUserContext,
- workflow_attachment: Optional[UploadFile],
- workflow_url: Optional[str],
+ workflow_attachment: UploadFile | None,
+ workflow_url: str | None,
) -> dict[str, Any]:
"""Load workflow content from attachment or URL.
@@ -440,15 +439,15 @@ class WesService(ServiceBase):
def submit_run(
self,
trans: ProvidesUserContext,
- workflow_params: Optional[str] = None,
- workflow_type: Optional[str] = None,
- workflow_type_version: Optional[str] = None,
- workflow_url: Optional[str] = None,
- workflow_engine_parameters: Optional[str] = None,
- workflow_engine: Optional[str] = None,
- workflow_engine_version: Optional[str] = None,
- tags: Optional[str] = None,
- workflow_attachment: Optional[UploadFile] = None,
+ workflow_params: str | None = None,
+ workflow_type: str | None = None,
+ workflow_type_version: str | None = None,
+ workflow_url: str | None = None,
+ workflow_engine_parameters: str | None = None,
+ workflow_engine: str | None = None,
+ workflow_engine_version: str | None = None,
+ tags: str | None = None,
+ workflow_attachment: UploadFile | None = None,
) -> RunId:
"""Submit a new workflow run.
@@ -576,7 +575,7 @@ class WesService(ServiceBase):
self,
trans: ProvidesUserContext,
page_size: int = 10,
- page_token: Optional[str] = None,
+ page_token: str | None = None,
) -> RunListResponse:
"""List workflow runs for the user with keyset pagination.
@@ -746,7 +745,7 @@ class WesService(ServiceBase):
self,
trans: ProvidesUserContext,
invocation_id: int,
- last_token: Optional[TaskKeysetToken],
+ last_token: TaskKeysetToken | None,
limit: int,
) -> list[dict]:
"""Fetch paginated task rows using composite keyset pagination.
@@ -874,7 +873,7 @@ class WesService(ServiceBase):
trans: ProvidesUserContext,
run_id: int,
page_size: int = 10,
- page_token: Optional[str] = None,
+ page_token: str | None = None,
) -> TaskListResponse:
"""Get paginated list of tasks for a workflow run.
@@ -1109,7 +1108,7 @@ class WesService(ServiceBase):
self,
trans: SessionRequestContext,
invocation: WorkflowInvocation,
- original_request: Optional[RunRequest] = None,
+ original_request: RunRequest | None = None,
) -> RunLog:
"""Convert a Galaxy WorkflowInvocation to a WES RunLog.
diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py
index dcb27917807..baaf3371535 100644
--- a/lib/galaxy/webapps/galaxy/services/workflows.py
+++ b/lib/galaxy/webapps/galaxy/services/workflows.py
@@ -2,8 +2,6 @@ import logging
import re
from typing import (
Any,
- Optional,
- Union,
)
from pydantic import UUID4
@@ -72,8 +70,8 @@ def _sanitize_output_label(label: str) -> str:
def _validate_input_names(
- dataset_names: Optional[list[str]],
- dataset_collection_names: Optional[list[str]],
+ dataset_names: list[str] | None,
+ dataset_collection_names: list[str] | None,
) -> None:
"""Validate user-supplied workflow input names (step labels).
@@ -117,7 +115,7 @@ class WorkflowsService(ServiceBase):
trans: ProvidesUserContext,
payload: WorkflowIndexPayload,
include_total_count: bool = False,
- ) -> tuple[list[dict[str, Any]], Optional[int]]:
+ ) -> tuple[list[dict[str, Any]], int | None]:
user = trans.user
missing_tools = payload.missing_tools
query, total_matches = self._workflows_manager.index_query(trans, payload, include_total_count)
@@ -178,7 +176,7 @@ class WorkflowsService(ServiceBase):
trans,
workflow_id,
payload: InvokeWorkflowPayload,
- ) -> Union[WorkflowInvocationResponse, list[WorkflowInvocationResponse]]:
+ ) -> WorkflowInvocationResponse | list[WorkflowInvocationResponse]:
if trans.anonymous:
raise exceptions.AuthenticationRequired("You need to be logged in to run workflows.")
trans.check_user_activation()
@@ -453,7 +451,7 @@ class WorkflowsService(ServiceBase):
return None
def _create_landing_request_association(
- self, trans: ProvidesUserContext, landing_uuid: Optional[UUID4], invocations: list[WorkflowInvocation]
+ self, trans: ProvidesUserContext, landing_uuid: UUID4 | None, invocations: list[WorkflowInvocation]
):
"""Create association between landing request and workflow invocations."""
# Look up the workflow landing request by UUID
diff --git a/lib/galaxy/webapps/openapi/_compat/v2.py b/lib/galaxy/webapps/openapi/_compat/v2.py
index c3796db4c15..1515f9e0f58 100644
--- a/lib/galaxy/webapps/openapi/_compat/v2.py
+++ b/lib/galaxy/webapps/openapi/_compat/v2.py
@@ -3,7 +3,6 @@ from typing import (
Any,
cast,
Literal,
- Union,
)
from fastapi._compat.v2 import (
@@ -25,7 +24,7 @@ def get_definitions(
fields: Sequence[ModelField],
model_name_map: ModelNameMap,
separate_input_output_schemas: bool = True,
- schema_generator: Union[GenerateJsonSchema, None] = None,
+ schema_generator: GenerateJsonSchema | None = None,
) -> tuple[
dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue],
dict[str, dict[str, Any]],
diff --git a/lib/galaxy/webapps/openapi/utils.py b/lib/galaxy/webapps/openapi/utils.py
index 74d5f634e2d..4b528f0b7f5 100644
--- a/lib/galaxy/webapps/openapi/utils.py
+++ b/lib/galaxy/webapps/openapi/utils.py
@@ -6,8 +6,6 @@ from collections.abc import Sequence
from inspect import signature
from typing import (
Any,
- Optional,
- Union,
)
from fastapi import routing
@@ -33,18 +31,18 @@ def get_openapi(
title: str,
version: str,
openapi_version: str = "3.1.0",
- summary: Optional[str] = None,
- description: Optional[str] = None,
+ summary: str | None = None,
+ description: str | None = None,
routes: Sequence[BaseRoute],
- webhooks: Optional[Sequence[BaseRoute]] = None,
- tags: Optional[list[dict[str, Any]]] = None,
- servers: Optional[list[dict[str, Union[str, Any]]]] = None,
- terms_of_service: Optional[str] = None,
- contact: Optional[dict[str, Union[str, Any]]] = None,
- license_info: Optional[dict[str, Union[str, Any]]] = None,
+ webhooks: Sequence[BaseRoute] | None = None,
+ tags: list[dict[str, Any]] | None = None,
+ servers: list[dict[str, str | Any]] | None = None,
+ terms_of_service: str | None = None,
+ contact: dict[str, str | Any] | None = None,
+ license_info: dict[str, str | Any] | None = None,
separate_input_output_schemas: bool = True,
- external_docs: Optional[dict[str, Any]] = None,
- schema_generator: Optional[GenerateJsonSchema] = None,
+ external_docs: dict[str, Any] | None = None,
+ schema_generator: GenerateJsonSchema | None = None,
) -> dict[str, Any]:
info: dict[str, Any] = {"title": title, "version": version}
if summary:
diff --git a/lib/galaxy/work/context.py b/lib/galaxy/work/context.py
index d1a5831ddfc..4d2a1b0f44a 100644
--- a/lib/galaxy/work/context.py
+++ b/lib/galaxy/work/context.py
@@ -40,11 +40,11 @@ class WorkRequestContext(ProvidesHistoryContext):
workflow_building_mode=False,
url_builder=None,
galaxy_session: Optional["GalaxySession"] = None,
- short_term_cache: Optional[dict[tuple[Hashable, ...], Any]] = None,
+ short_term_cache: dict[tuple[Hashable, ...], Any] | None = None,
):
self._app = app
self.__user = user
- self.__user_current_roles: Optional[list[Role]] = None
+ self.__user_current_roles: list[Role] | None = None
self.__history = history
self._url_builder = url_builder
# When proxying an existing transaction (see ``proxy_work_context_for_history``)
@@ -145,13 +145,13 @@ class GalaxyAbstractResponse:
self,
key: str,
value: str = "",
- max_age: Optional[int] = None,
- expires: Optional[int] = None,
+ max_age: int | None = None,
+ expires: int | None = None,
path: str = "/",
- domain: Optional[str] = None,
+ domain: str | None = None,
secure: bool = False,
httponly: bool = False,
- samesite: Optional[Literal["lax", "strict", "none"]] = "lax",
+ samesite: Literal["lax", "strict", "none"] | None = "lax",
) -> None:
"""Set a cookie."""
diff --git a/lib/galaxy/workflow/completion_hooks/__init__.py b/lib/galaxy/workflow/completion_hooks/__init__.py
index fd17ff7db29..860d410b5bc 100644
--- a/lib/galaxy/workflow/completion_hooks/__init__.py
+++ b/lib/galaxy/workflow/completion_hooks/__init__.py
@@ -16,7 +16,6 @@ Hooks are automatically discovered via the plugin_type attribute.
import logging
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -75,7 +74,7 @@ class WorkflowCompletionHookRegistry:
"""
return list(self.hooks.keys())
- def get_hook(self, name: str) -> Optional[WorkflowCompletionHook]:
+ def get_hook(self, name: str) -> WorkflowCompletionHook | None:
"""
Get a hook instance by name.
diff --git a/lib/galaxy/workflow/completion_hooks/export.py b/lib/galaxy/workflow/completion_hooks/export.py
index c6bd47b7562..58bea7a1be5 100644
--- a/lib/galaxy/workflow/completion_hooks/export.py
+++ b/lib/galaxy/workflow/completion_hooks/export.py
@@ -11,7 +11,6 @@ __all__ = ("ExportToFileSourceHook",)
from typing import (
Any,
- Optional,
TYPE_CHECKING,
)
@@ -153,7 +152,7 @@ class ExportToFileSourceHook(WorkflowCompletionHook):
export_association.task_uuid = result.id
self.app.model.context.commit()
- def _get_export_config(self, invocation) -> "Optional[dict[str, Any]]":
+ def _get_export_config(self, invocation) -> "dict[str, Any] | None":
"""
Extract export configuration from invocation on_complete actions.
diff --git a/lib/galaxy/workflow/completion_hooks/notification.py b/lib/galaxy/workflow/completion_hooks/notification.py
index 4ab247a477d..3b714478b7f 100644
--- a/lib/galaxy/workflow/completion_hooks/notification.py
+++ b/lib/galaxy/workflow/completion_hooks/notification.py
@@ -133,13 +133,12 @@ class SendNotificationHook(WorkflowCompletionHook):
The formatted message string with Markdown.
"""
invocation = completion.workflow_invocation
- summary = completion.job_state_summary or {}
lines = [
f"Your workflow **{workflow_name}** has completed.",
]
- if summary:
+ if summary := completion.job_state_summary or {}:
lines.extend(["", "**Job Summary:**", ""])
for state, count in sorted(summary.items()):
lines.append(f"- {state}: {count}")
diff --git a/lib/galaxy/workflow/extract.py b/lib/galaxy/workflow/extract.py
index 0eb315fd44e..ed04aad4d8c 100644
--- a/lib/galaxy/workflow/extract.py
+++ b/lib/galaxy/workflow/extract.py
@@ -9,7 +9,6 @@ from typing import (
Any,
cast,
Literal,
- Optional,
)
from sqlalchemy import select
@@ -82,13 +81,13 @@ def _connect(step: WorkflowStep, input_name: str, source: tuple[WorkflowStep, st
def extract_workflow(
trans: ProvidesHistoryContext,
user: User,
- history: Optional[History] = None,
- job_ids: Optional[list[int]] = None,
- dataset_ids: Optional[list[int]] = None,
- dataset_collection_ids: Optional[list[int]] = None,
- workflow_name: Optional[str] = None,
- dataset_names: Optional[list[str]] = None,
- dataset_collection_names: Optional[list[str]] = None,
+ history: History | None = None,
+ job_ids: list[int] | None = None,
+ dataset_ids: list[int] | None = None,
+ dataset_collection_ids: list[int] | None = None,
+ workflow_name: str | None = None,
+ dataset_names: list[str] | None = None,
+ dataset_collection_names: list[str] | None = None,
) -> StoredWorkflow:
steps = extract_steps(
trans,
@@ -105,7 +104,7 @@ def extract_workflow(
def _finalize_workflow(
trans: ProvidesHistoryContext,
user: User,
- workflow_name: Optional[str],
+ workflow_name: str | None,
steps: list[WorkflowStep],
) -> StoredWorkflow:
workflow = model.Workflow()
@@ -131,12 +130,12 @@ def _finalize_workflow(
def extract_steps(
trans: ProvidesHistoryContext,
- history: Optional[History] = None,
- job_ids: Optional[list[int]] = None,
- dataset_ids: Optional[list[int]] = None,
- dataset_collection_ids: Optional[list[int]] = None,
- dataset_names: Optional[list[str]] = None,
- dataset_collection_names: Optional[list[str]] = None,
+ history: History | None = None,
+ job_ids: list[int] | None = None,
+ dataset_ids: list[int] | None = None,
+ dataset_collection_ids: list[int] | None = None,
+ dataset_names: list[str] | None = None,
+ dataset_collection_names: list[str] | None = None,
) -> list[WorkflowStep]:
# Ensure job_ids and dataset_ids are lists (possibly empty)
job_ids = listify(job_ids)
@@ -217,7 +216,7 @@ def extract_steps(
if _skip_output_assoc_name(assoc_name):
continue
if job in summary.implicit_map_jobs:
- hid: Optional[int] = None
+ hid: int | None = None
for implicit_pair in jobs[job]:
query_assoc_name, dataset_collection = implicit_pair
if query_assoc_name == assoc_name or assoc_name.startswith(
@@ -254,7 +253,7 @@ class FakeJob:
self.id = f"fake_{dataset.id}"
self.name = self._guess_name_from_dataset(dataset)
- def _guess_name_from_dataset(self, dataset: HistoryDatasetAssociation) -> Optional[str]:
+ def _guess_name_from_dataset(self, dataset: HistoryDatasetAssociation) -> str | None:
"""Tries to guess the name of the fake job from the dataset associations."""
if dataset.copied_from_history_dataset_association:
return "Import from History"
@@ -267,7 +266,7 @@ class DatasetCollectionCreationJob:
def __init__(self, dataset_collection: HistoryDatasetCollectionAssociation) -> None:
self.is_fake = True
self.id = f"fake_{dataset_collection.id}"
- self.from_jobs: Optional[list[Job]] = None
+ self.from_jobs: list[Job] | None = None
self.name = "Dataset Collection Creation"
self.disabled_why = "Dataset collection created in a way not compatible with workflows"
@@ -277,8 +276,8 @@ class DatasetCollectionCreationJob:
def summarize(
- trans: ProvidesHistoryContext, history: Optional[History] = None
-) -> tuple[dict[Any, list[tuple[Optional[str], HistoryItem]]], set[str]]:
+ trans: ProvidesHistoryContext, history: History | None = None
+) -> tuple[dict[Any, list[tuple[str | None, HistoryItem]]], set[str]]:
"""Return mapping of job description to datasets for active items in
supplied history - needed for building workflow from a history.
@@ -295,7 +294,7 @@ class BaseWorkflowSummary:
self.trans = trans
self.warnings: set[str] = set()
- def _check_state(self, hda: HistoryDatasetAssociation) -> Optional[HistoryDatasetAssociation]:
+ def _check_state(self, hda: HistoryDatasetAssociation) -> HistoryDatasetAssociation | None:
# FIXME: Create "Dataset.is_finished"
if hda.state in ("new", "running", "queued"):
self.warnings.add(WARNING_SOME_DATASETS_NOT_READY)
@@ -304,13 +303,13 @@ class BaseWorkflowSummary:
class WorkflowSummary(BaseWorkflowSummary):
- def __init__(self, trans: ProvidesHistoryContext, history: Optional[History]) -> None:
+ def __init__(self, trans: ProvidesHistoryContext, history: History | None) -> None:
super().__init__(trans)
if not history:
history = trans.history
assert history is not None
self.history: History = history
- self.jobs: dict[Any, list[tuple[Optional[str], HistoryItem]]] = {}
+ self.jobs: dict[Any, list[tuple[str | None, HistoryItem]]] = {}
self.job_id2representative_job: dict[int, Job] = {} # map a non-fake job id to its representative job
self.implicit_map_jobs: list[Job] = []
self.collection_types: dict[int, str] = {}
@@ -548,13 +547,13 @@ def extract_workflow_by_ids(
user: User,
workflow_name: str,
job_manager: JobManager,
- job_ids: Optional[list[int]] = None,
- implicit_collection_jobs_ids: Optional[list[int]] = None,
- hda_ids: Optional[list[int]] = None,
- hdca_ids: Optional[list[int]] = None,
- dataset_names: Optional[list[str]] = None,
- dataset_collection_names: Optional[list[str]] = None,
- output_labels: Optional[list[Any]] = None,
+ job_ids: list[int] | None = None,
+ implicit_collection_jobs_ids: list[int] | None = None,
+ hda_ids: list[int] | None = None,
+ hdca_ids: list[int] | None = None,
+ dataset_names: list[str] | None = None,
+ dataset_collection_names: list[str] | None = None,
+ output_labels: list[Any] | None = None,
) -> StoredWorkflow:
"""ID-based variant of :func:`extract_workflow`."""
steps = extract_steps_by_ids(
@@ -603,9 +602,9 @@ def normalize_output_label_key(trans: ProvidesHistoryContext, kind: OutputLabelK
def collect_output_label_targets(
trans: ProvidesHistoryContext,
- job_manager: Optional[JobManager] = None,
- job_ids: Optional[list[int]] = None,
- implicit_collection_jobs_ids: Optional[list[int]] = None,
+ job_manager: JobManager | None = None,
+ job_ids: list[int] | None = None,
+ implicit_collection_jobs_ids: list[int] | None = None,
) -> dict[OutputLabelKey, OutputLabelTarget]:
"""Collect concrete outputs produced by the selected extraction steps."""
job_ids = list(job_ids or [])
@@ -648,14 +647,14 @@ def collect_output_label_targets(
def extract_steps_by_ids(
trans: ProvidesHistoryContext,
- job_manager: Optional[JobManager] = None,
- job_ids: Optional[list[int]] = None,
- implicit_collection_jobs_ids: Optional[list[int]] = None,
- hda_ids: Optional[list[int]] = None,
- hdca_ids: Optional[list[int]] = None,
- dataset_names: Optional[list[str]] = None,
- dataset_collection_names: Optional[list[str]] = None,
- output_labels: Optional[list[Any]] = None,
+ job_manager: JobManager | None = None,
+ job_ids: list[int] | None = None,
+ implicit_collection_jobs_ids: list[int] | None = None,
+ hda_ids: list[int] | None = None,
+ hdca_ids: list[int] | None = None,
+ dataset_names: list[str] | None = None,
+ dataset_collection_names: list[str] | None = None,
+ output_labels: list[Any] | None = None,
) -> list[WorkflowStep]:
"""ID-based variant of :func:`extract_steps`.
diff --git a/lib/galaxy/workflow/modules.py b/lib/galaxy/workflow/modules.py
index 6a465c3e397..32589a21c07 100644
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -16,9 +16,7 @@ from typing import (
Any,
cast,
get_args,
- Optional,
TYPE_CHECKING,
- Union,
)
from typing_extensions import TypedDict
@@ -182,7 +180,7 @@ class ConditionalStepWhen(BooleanToolParameter):
def to_cwl(
- value, hda_references, step: Optional[WorkflowStep] = None, compute_environment: Optional[ComputeEnvironment] = None
+ value, hda_references, step: WorkflowStep | None = None, compute_environment: ComputeEnvironment | None = None
):
element_identifier = None
if isinstance(value, NoReplacement):
@@ -486,7 +484,7 @@ class WorkflowModule:
def get_runtime_state(self) -> DefaultToolState:
raise TypeError("Abstract method")
- def get_runtime_inputs(self, step, connections: Optional[Iterable[WorkflowStepConnection]] = None):
+ def get_runtime_inputs(self, step, connections: Iterable[WorkflowStepConnection] | None = None):
"""Used internally by modules and when displaying inputs in workflow
editor and run workflow templates.
"""
@@ -561,7 +559,7 @@ class WorkflowModule:
def execute(
self, trans, progress: "WorkflowProgress", invocation_step, use_cached_job: bool = False
- ) -> Optional[bool]:
+ ) -> bool | None:
"""Execute the given workflow invocation step.
Use the supplied workflow progress object to track outputs, find
@@ -729,12 +727,12 @@ class SubWorkflowModule(WorkflowModule):
# - Second pass actually turn RuntimeInputs into inputs if possible.
type = "subworkflow"
name = "Subworkflow"
- _modules: Optional[list[Any]] = None
+ _modules: list[Any] | None = None
subworkflow: Workflow
def __init__(self, trans, content_id=None, **kwds):
super().__init__(trans, content_id, **kwds)
- self.post_job_actions: Optional[dict[str, Any]] = None
+ self.post_job_actions: dict[str, Any] | None = None
@classmethod
def from_dict(Class, trans, d, **kwds):
@@ -874,7 +872,7 @@ class SubWorkflowModule(WorkflowModule):
def execute(
self, trans, progress: "WorkflowProgress", invocation_step: WorkflowInvocationStep, use_cached_job: bool = False
- ) -> Optional[bool]:
+ ) -> bool | None:
"""Execute the given workflow step in the given workflow invocation.
Use the supplied workflow progress object to track outputs, find
inputs, etc...
@@ -892,7 +890,7 @@ class SubWorkflowModule(WorkflowModule):
assert len(progress.when_values) == 1, "Got more than 1 when value, this shouldn't be possible"
iteration_elements_iter = [(None, progress.when_values[0] if progress.when_values else None)]
- when_values: list[Union[bool, None]] = []
+ when_values: list[bool | None] = []
for iteration_elements, when_value in iteration_elements_iter:
if when_value is False or not step.when_expression:
# We're skipping this step (when==False) or we keep
@@ -953,7 +951,7 @@ class SubWorkflowModule(WorkflowModule):
state.inputs = {}
return state
- def get_runtime_inputs(self, step, connections: Optional[Iterable[WorkflowStepConnection]] = None):
+ def get_runtime_inputs(self, step, connections: Iterable[WorkflowStepConnection] | None = None):
inputs = {}
for step in self.subworkflow.steps:
if step.type == "tool":
@@ -1059,7 +1057,7 @@ class InputModule(WorkflowModule):
def execute(
self, trans, progress: "WorkflowProgress", invocation_step, use_cached_job: bool = False
- ) -> Optional[bool]:
+ ) -> bool | None:
invocation = invocation_step.workflow_invocation
step = invocation_step.workflow_step
input_value = step.state.inputs["input"]
@@ -1106,7 +1104,7 @@ class InputModule(WorkflowModule):
optional = self.default_optional
rval["optional"] = optional
if "format" in inputs:
- formats: Optional[list[str]] = listify(inputs["format"])
+ formats: list[str] | None = listify(inputs["format"])
else:
formats = None
if formats:
@@ -1158,7 +1156,7 @@ class InputDataModule(InputModule):
filter_set = {"data"}
return ", ".join(sorted(filter_set))
- def get_runtime_inputs(self, step, connections: Optional[Iterable[WorkflowStepConnection]] = None):
+ def get_runtime_inputs(self, step, connections: Iterable[WorkflowStepConnection] | None = None):
parameter_def = self._parse_state_into_dict()
optional = parameter_def["optional"]
tag = parameter_def["tag"]
@@ -1220,7 +1218,7 @@ class InputDataCollectionModule(InputModule):
validate_column_definitions(column_definitions)
return None
- def get_runtime_inputs(self, step, connections: Optional[Iterable[WorkflowStepConnection]] = None):
+ def get_runtime_inputs(self, step, connections: Iterable[WorkflowStepConnection] | None = None):
parameter_def = self._parse_state_into_dict()
collection_type = parameter_def["collection_type"]
optional = parameter_def["optional"]
@@ -1395,7 +1393,6 @@ class InputParameterModule(WorkflowModule):
return add_validators_repeat
if param_type == "text":
-
specify_multiple_source = dict(
name="multiple",
label="Allow multiple selection",
@@ -1412,7 +1409,7 @@ class InputParameterModule(WorkflowModule):
**when_this_type.inputs,
}
- restrict_how_source: dict[str, Union[str, list[dict[str, Union[str, bool]]]]] = dict(
+ restrict_how_source: dict[str, str | list[dict[str, str | bool]]] = dict(
name="how", label="Restrict Text Values?", type="select"
)
restrict_how_source["options"] = [
@@ -1573,7 +1570,7 @@ class InputParameterModule(WorkflowModule):
]
)
- options: Optional[list[OptionDict]] = None
+ options: list[OptionDict] | None = None
if static_options and len(static_options) == 1:
# If we are connected to a single option, just use it as is so order is preserved cleanly and such.
options = [
@@ -1601,7 +1598,7 @@ class InputParameterModule(WorkflowModule):
except Exception:
log.debug("Failed to generate options for text parameter, falling back to free text.", exc_info=True)
- def get_runtime_inputs(self, step, connections: Optional[Iterable[WorkflowStepConnection]] = None):
+ def get_runtime_inputs(self, step, connections: Iterable[WorkflowStepConnection] | None = None):
parameter_def = self._parse_state_into_dict()
parameter_type = parameter_def["parameter_type"]
optional = parameter_def["optional"]
@@ -1611,7 +1608,7 @@ class InputParameterModule(WorkflowModule):
raise ValueError("Invalid parameter type for workflow parameters encountered.")
# Optional parameters for tool input source definition.
- parameter_kwds: dict[str, Union[str, list[dict[str, Any]]]] = {}
+ parameter_kwds: dict[str, str | list[dict[str, Any]]] = {}
if "multiple" in parameter_def:
parameter_kwds["multiple"] = parameter_def["multiple"]
@@ -1705,7 +1702,7 @@ class InputParameterModule(WorkflowModule):
progress: "WorkflowProgress",
invocation_step: "WorkflowInvocationStep",
use_cached_job: bool = False,
- ) -> Optional[bool]:
+ ) -> bool | None:
input_value = self.get_input_value(progress, invocation_step)
input_param = self.get_runtime_inputs(self)["input"]
# TODO: raise DelayedWorkflowEvaluation if replacement not ready ? Need test
@@ -1937,7 +1934,7 @@ class PauseModule(WorkflowModule):
def execute(
self, trans, progress: "WorkflowProgress", invocation_step, use_cached_job: bool = False
- ) -> Optional[bool]:
+ ) -> bool | None:
step = invocation_step.workflow_step
progress.mark_step_outputs_delayed(step, why="executing pause step")
return None
@@ -2127,7 +2124,7 @@ class PickValueModule(WorkflowModule):
def execute(
self, trans, progress: "WorkflowProgress", invocation_step, use_cached_job: bool = False
- ) -> Optional[bool]:
+ ) -> bool | None:
step = invocation_step.workflow_step
mode = step.tool_inputs.get("mode", "first_non_null") if step.tool_inputs else "first_non_null"
all_inputs = self.get_all_inputs()
@@ -2343,9 +2340,9 @@ def _capture_workflow_tool_request_state(
resolve_execution_state: Callable[[Any], Any],
param_combinations: list[dict[str, Any]],
) -> tuple[
- Optional[RequestInternalDereferencedToolState],
- Optional[list[JobInternalToolState]],
- Optional[ToolRequest],
+ RequestInternalDereferencedToolState | None,
+ list[JobInternalToolState] | None,
+ ToolRequest | None,
]:
"""Synthesize + validate request_internal for a workflow tool step and
persist it as a :class:`ToolRequest` row.
@@ -2368,9 +2365,9 @@ def _capture_workflow_tool_request_state(
parameters = getattr(tool, "parameters", None)
if parameters is None:
return None, None, None
- request_internal: Optional[RequestInternalToolState] = None
- validated_template: Optional[RequestInternalDereferencedToolState] = None
- validated_combinations: Optional[list[JobInternalToolState]] = None
+ request_internal: RequestInternalToolState | None = None
+ validated_template: RequestInternalDereferencedToolState | None = None
+ validated_combinations: list[JobInternalToolState] | None = None
request_state = WorkflowToolRequestState.NOT_VALIDATED
try:
parameter_bundle = ToolParameterBundleModel(parameters=parameters)
@@ -2491,7 +2488,7 @@ class ToolModule(WorkflowModule):
self.tool_id = tool_id
self.tool_version = str(tool_version) if tool_version else None
self.tool_uuid = tool_uuid
- self.tool: Optional[Tool] = None
+ self.tool: Tool | None = None
if getattr(trans.app, "toolbox", None):
if trans.user and tool_uuid:
self.tool = trans.app.toolbox.get_unprivileged_tool_or_none(trans.user, tool_uuid=tool_uuid)
@@ -2748,7 +2745,7 @@ class ToolModule(WorkflowModule):
collection_type = rule_set.collection_type
extra_kwds["collection_type"] = collection_type
extra_kwds["collection_type_source"] = tool_output.structure.collection_type_source
- formats: list[Optional[str]] = ["input"] # TODO: fix
+ formats: list[str | None] = ["input"] # TODO: fix
elif (
isinstance(tool_output, (ToolOutput, ToolExpressionOutput, ToolOutputCollection))
and tool_output.format_source is not None
@@ -2903,7 +2900,7 @@ class ToolModule(WorkflowModule):
state.inputs = self.state.inputs
return state
- def get_runtime_inputs(self, step, connections: Optional[Iterable[WorkflowStepConnection]] = None):
+ def get_runtime_inputs(self, step, connections: Iterable[WorkflowStepConnection] | None = None):
return self.get_inputs()
def compute_runtime_state(self, trans, step=None, step_updates=None, replace_default_values=False):
@@ -2945,7 +2942,7 @@ class ToolModule(WorkflowModule):
progress: "WorkflowProgress",
invocation_step: "WorkflowInvocationStep",
use_cached_job: bool = False,
- ) -> Optional[bool]:
+ ) -> bool | None:
invocation = invocation_step.workflow_invocation
step = invocation_step.workflow_step
tool = trans.app.toolbox.get_tool(
@@ -3006,7 +3003,7 @@ class ToolModule(WorkflowModule):
def callback(input, prefixed_name: str, **kwargs):
input_dict = all_inputs_by_name[prefixed_name]
- replacement: Union[model.Dataset, NoReplacement, PromoteCollectionElementToCollectionAdapter] = (
+ replacement: model.Dataset | NoReplacement | PromoteCollectionElementToCollectionAdapter = (
NO_REPLACEMENT
)
if iteration_elements and prefixed_name in iteration_elements:
@@ -3031,7 +3028,7 @@ class ToolModule(WorkflowModule):
if replacement is not NO_REPLACEMENT:
if not isinstance(input, BaseDataToolParameter):
# Probably a parameter that can be replaced
- dataset_instance: Optional[model.DatasetInstance] = None
+ dataset_instance: model.DatasetInstance | None = None
if isinstance(replacement, model.DatasetCollectionElement):
dataset_instance = replacement.hda
elif isinstance(replacement, model.DatasetInstance):
@@ -3124,7 +3121,7 @@ class ToolModule(WorkflowModule):
)
complete = False
- completed_jobs: dict[int, Optional[Job]] = tool.completed_jobs(
+ completed_jobs: dict[int, Job | None] = tool.completed_jobs(
trans,
use_cached_job,
param_combinations,
@@ -3173,7 +3170,7 @@ class ToolModule(WorkflowModule):
raise DelayedWorkflowEvaluation(why=delayed_why)
progress.record_executed_job_count(len(execution_tracker.successful_jobs))
- step_outputs: dict[str, Union[model.HistoryDatasetCollectionAssociation, model.HistoryDatasetAssociation]] = {}
+ step_outputs: dict[str, model.HistoryDatasetCollectionAssociation | model.HistoryDatasetAssociation] = {}
if collection_info:
step_outputs.update(execution_tracker.implicit_collections)
else:
@@ -3256,7 +3253,7 @@ class ToolModule(WorkflowModule):
self.trans, self.trans.sa_session, pja, step_inputs, step_outputs, replacement_dict
)
- def _resolve_credentials_context(self, tool: "Tool") -> Optional[CredentialsContext]:
+ def _resolve_credentials_context(self, tool: "Tool") -> CredentialsContext | None:
"""Auto-resolve the user's current credentials for a tool in workflow execution."""
if not tool.credentials:
return None
diff --git a/lib/galaxy/workflow/refactor/schema.py b/lib/galaxy/workflow/refactor/schema.py
index edef0d8b8b5..ad64c2c2992 100644
--- a/lib/galaxy/workflow/refactor/schema.py
+++ b/lib/galaxy/workflow/refactor/schema.py
@@ -3,8 +3,6 @@ from typing import (
Annotated,
Any,
Literal,
- Optional,
- Union,
)
from pydantic import (
@@ -32,7 +30,7 @@ class StepReferenceByLabel(BaseModel):
label: str = Field(description=LABEL_DESCRIPTION)
-step_reference_union = Union[StepReferenceByOrderIndex, StepReferenceByLabel]
+step_reference_union = StepReferenceByOrderIndex | StepReferenceByLabel
class InputReferenceByOrderIndex(StepReferenceByOrderIndex):
@@ -43,18 +41,18 @@ class InputReferenceByLabel(StepReferenceByLabel):
input_name: str = input_name_field
-input_reference_union = Union[InputReferenceByOrderIndex, InputReferenceByLabel]
+input_reference_union = InputReferenceByOrderIndex | InputReferenceByLabel
class OutputReferenceByOrderIndex(StepReferenceByOrderIndex):
- output_name: Optional[str] = output_name_field
+ output_name: str | None = output_name_field
class OutputReferenceByLabel(StepReferenceByLabel):
- output_name: Optional[str] = output_name_field
+ output_name: str | None = output_name_field
-output_reference_union = Union[OutputReferenceByOrderIndex, OutputReferenceByLabel]
+output_reference_union = OutputReferenceByOrderIndex | OutputReferenceByLabel
class Position(BaseModel):
@@ -114,12 +112,12 @@ class AddStepAction(BaseAction):
action_type: Literal["add_step"]
type: str = Field(description="Module type of the step to add, see galaxy.workflow.modules for available types.")
- tool_state: Optional[dict[str, Any]] = None
- label: Optional[str] = Field(
+ tool_state: dict[str, Any] | None = None
+ label: str | None = Field(
None,
description="A unique label for the step being added, must be distinct from the labels already present in the workflow.",
)
- position: Optional[Position] = Field(None, description="The location of the step in the Galaxy workflow editor.")
+ position: Position | None = Field(None, description="The location of the step in the Galaxy workflow editor.")
class ConnectAction(BaseAction):
@@ -137,28 +135,28 @@ class DisconnectAction(BaseAction):
class AddInputAction(BaseAction):
action_type: Literal["add_input"]
type: str
- label: Optional[str] = None
- position: Optional[Position] = None
- collection_type: Optional[str] = None
- restrictions: Optional[list[str]] = None
- restrict_on_connections: Optional[bool] = None
- suggestions: Optional[list[str]] = None
- optional: Optional[bool] = False
- default: Optional[Any] = None # this probably needs to be revisited when we have more complex field types
+ label: str | None = None
+ position: Position | None = None
+ collection_type: str | None = None
+ restrictions: list[str] | None = None
+ restrict_on_connections: bool | None = None
+ suggestions: list[str] | None = None
+ optional: bool | None = False
+ default: Any | None = None # this probably needs to be revisited when we have more complex field types
class ExtractInputAction(BaseAction):
action_type: Literal["extract_input"]
input: input_reference_union
- label: Optional[str] = None
- position: Optional[Position] = None
+ label: str | None = None
+ position: Position | None = None
class ExtractUntypedParameter(BaseAction):
action_type: Literal["extract_untyped_parameter"]
name: str
- label: Optional[str] = None # defaults to name if unset
- position: Optional[Position] = None
+ label: str | None = None # defaults to name if unset
+ position: Position | None = None
class RemoveUnlabeledWorkflowOutputs(BaseAction):
@@ -214,45 +212,45 @@ class UpgradeSubworkflowAction(BaseAction):
step: step_reference_union = step_target_field
# Once we start storing these actions in the database, this needs to be decoded
# before adding it into the database.
- content_id: Optional[str] = None
+ content_id: str | None = None
class UpgradeToolAction(BaseAction):
action_type: Literal["upgrade_tool"]
step: step_reference_union = step_target_field
- tool_version: Optional[str] = None
+ tool_version: str | None = None
class UpgradeAllStepsAction(BaseAction):
action_type: Literal["upgrade_all_steps"]
-union_action_classes = Union[
- AddInputAction,
- AddStepAction,
- ConnectAction,
- DisconnectAction,
- ExtractInputAction,
- ExtractUntypedParameter,
- FileDefaultsAction,
- FillStepDefaultsAction,
- UpdateAnnotationAction,
- UpdateCreatorAction,
- UpdateNameAction,
- UpdateLicenseAction,
- UpdateOutputLabelAction,
- UpdateReportAction,
- UpdateStepLabelAction,
- UpdateStepPositionAction,
- UpgradeSubworkflowAction,
- UpgradeToolAction,
- UpgradeAllStepsAction,
- RemoveUnlabeledWorkflowOutputs,
-]
+union_action_classes = (
+ AddInputAction
+ | AddStepAction
+ | ConnectAction
+ | DisconnectAction
+ | ExtractInputAction
+ | ExtractUntypedParameter
+ | FileDefaultsAction
+ | FillStepDefaultsAction
+ | UpdateAnnotationAction
+ | UpdateCreatorAction
+ | UpdateNameAction
+ | UpdateLicenseAction
+ | UpdateOutputLabelAction
+ | UpdateReportAction
+ | UpdateStepLabelAction
+ | UpdateStepPositionAction
+ | UpgradeSubworkflowAction
+ | UpgradeToolAction
+ | UpgradeAllStepsAction
+ | RemoveUnlabeledWorkflowOutputs
+)
ACTION_CLASSES_BY_TYPE = {}
-for action_class in union_action_classes.__args__: # type: ignore[attr-defined]
+for action_class in union_action_classes.__args__:
action_type_def = action_class.model_json_schema()["properties"]["action_type"]
try:
# pydantic 1.8
@@ -290,34 +288,32 @@ step with the previously connected input.
class RefactorActionExecutionMessage(BaseModel):
message: str
message_type: RefactorActionExecutionMessageTypeEnum
- step_label: Optional[str] = Field(
+ step_label: str | None = Field(None, description=f"Reference to the step the message refers to. ${INPUT_REFERENCE}")
+ order_index: int | None = Field(
None, description=f"Reference to the step the message refers to. ${INPUT_REFERENCE}"
)
- order_index: Optional[int] = Field(
- None, description=f"Reference to the step the message refers to. ${INPUT_REFERENCE}"
- )
- input_name: Optional[str] = Field(
+ input_name: str | None = Field(
None,
description=f"""If this message is about an input to a step,
this field describes the target input name. ${INPUT_NAME_DESCRIPTION}""",
)
- output_name: Optional[str] = Field(
+ output_name: str | None = Field(
None,
description="""If this message is about an output to a step,
this field describes the target output name. The output name as defined by the workflow module corresponding to the step being referenced.
""",
)
- from_step_label: Optional[str] = Field(
+ from_step_label: str | None = Field(
None,
description="""For dropped connections these optional attributes refer to the output
side of the connection that was dropped.""",
)
- from_order_index: Optional[int] = Field(
+ from_order_index: int | None = Field(
None,
description="""For dropped connections these optional attributes refer to the output
side of the connection that was dropped.""",
)
- output_label: Optional[str] = Field(
+ output_label: str | None = Field(
None, description="If the message_type is workflow_output_drop_forced, this is the output label dropped."
)
diff --git a/lib/galaxy/workflow/run.py b/lib/galaxy/workflow/run.py
index c38334698e9..2156f24c986 100644
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -5,7 +5,6 @@ from typing import (
Any,
Optional,
TYPE_CHECKING,
- Union,
)
from boltons.iterutils import get_path
@@ -76,7 +75,7 @@ def __invoke(
trans: "WorkRequestContext",
workflow: "Workflow",
workflow_run_config: WorkflowRunConfig,
- workflow_invocation: Optional[WorkflowInvocation] = None,
+ workflow_invocation: WorkflowInvocation | None = None,
populate_state: bool = False,
) -> tuple[WorkflowOutputsType, WorkflowInvocation]:
"""Run the supplied workflow in the supplied target_history."""
@@ -129,7 +128,7 @@ def queue_invoke(
trans: "GalaxyWebTransaction",
workflow: "Workflow",
workflow_run_config: WorkflowRunConfig,
- request_params: Optional[dict[str, Any]] = None,
+ request_params: dict[str, Any] | None = None,
populate_state: bool = True,
flush: bool = True,
) -> WorkflowInvocation:
@@ -159,7 +158,7 @@ class WorkflowInvoker:
trans: "WorkRequestContext",
workflow: "Workflow",
workflow_run_config: WorkflowRunConfig,
- workflow_invocation: Optional[WorkflowInvocation] = None,
+ workflow_invocation: WorkflowInvocation | None = None,
progress: Optional["WorkflowProgress"] = None,
) -> None:
self.trans = trans
@@ -361,7 +360,7 @@ class WorkflowInvoker:
)
)
- def _invoke_step(self, invocation_step: WorkflowInvocationStep) -> Optional[bool]:
+ def _invoke_step(self, invocation_step: WorkflowInvocationStep) -> bool | None:
assert invocation_step.workflow_step.module
incomplete_or_none = invocation_step.workflow_step.module.execute(
self.trans,
@@ -398,7 +397,7 @@ class WorkflowProgress:
jobs_per_scheduling_iteration: int = -1,
copy_inputs_to_history: bool = False,
use_cached_job: bool = False,
- replacement_dict: Optional[dict[str, str]] = None,
+ replacement_dict: dict[str, str] | None = None,
subworkflow_collection_info=None,
when_values=None,
) -> None:
@@ -418,7 +417,7 @@ class WorkflowProgress:
self.when_values = when_values
@property
- def maximum_jobs_to_schedule_or_none(self) -> Optional[int]:
+ def maximum_jobs_to_schedule_or_none(self) -> int | None:
if self.jobs_per_scheduling_iteration > 0:
return self.jobs_per_scheduling_iteration - self.jobs_scheduled_this_iteration
else:
@@ -429,7 +428,7 @@ class WorkflowProgress:
def remaining_steps(
self,
- ) -> list[tuple["WorkflowStep", Optional[WorkflowInvocationStep]]]:
+ ) -> list[tuple["WorkflowStep", WorkflowInvocationStep | None]]:
# Previously computed and persisted step states.
step_states = self.workflow_invocation.step_states_by_step_id()
steps = self.workflow_invocation.workflow.steps
@@ -460,12 +459,9 @@ class WorkflowProgress:
return remaining_steps
def replacement_for_input(self, trans, step: "WorkflowStep", input_dict: dict[str, Any]):
- replacement: Union[
- NoReplacement,
- model.DatasetCollectionInstance,
- list[model.DatasetCollectionInstance],
- HistoryItem,
- ] = NO_REPLACEMENT
+ replacement: (
+ NoReplacement | model.DatasetCollectionInstance | list[model.DatasetCollectionInstance] | HistoryItem
+ ) = NO_REPLACEMENT
prefixed_name = input_dict["name"]
multiple = input_dict["multiple"]
is_data = input_dict["input_type"] in ["dataset", "dataset_collection"]
@@ -603,7 +599,7 @@ class WorkflowProgress:
def set_outputs_for_input(
self,
invocation_step: WorkflowInvocationStep,
- outputs: Optional[dict[str, Any]] = None,
+ outputs: dict[str, Any] | None = None,
already_persisted: bool = False,
) -> None:
step = invocation_step.workflow_step
@@ -690,7 +686,7 @@ class WorkflowProgress:
output = {"__class__": "NoReplacement"}
self.workflow_invocation.add_output(workflow_output, step, output)
- def mark_step_outputs_delayed(self, step: "WorkflowStep", why: Optional[str] = None) -> None:
+ def mark_step_outputs_delayed(self, step: "WorkflowStep", why: str | None = None) -> None:
if why:
message = f"Marking step {step.id} outputs of invocation {self.workflow_invocation.id} delayed ({why})"
log.debug(message)
diff --git a/lib/galaxy/workflow/run_request.py b/lib/galaxy/workflow/run_request.py
index ef0e63e7ec4..4996ea9aaa6 100644
--- a/lib/galaxy/workflow/run_request.py
+++ b/lib/galaxy/workflow/run_request.py
@@ -3,9 +3,7 @@ import logging
import uuid
from typing import (
Any,
- Optional,
TYPE_CHECKING,
- Union,
)
from pydantic import ValidationError
@@ -87,19 +85,19 @@ class WorkflowRunConfig:
def __init__(
self,
target_history: "History",
- replacement_dict: Optional[dict[str, Any]] = None,
- inputs: Optional[dict[int, Any]] = None,
- param_map: Optional[dict[int, Any]] = None,
+ replacement_dict: dict[str, Any] | None = None,
+ inputs: dict[int, Any] | None = None,
+ param_map: dict[int, Any] | None = None,
allow_tool_state_corrections: bool = False,
copy_inputs_to_history: bool = False,
use_cached_job: bool = False,
- resource_params: Optional[dict[int, Any]] = None,
+ resource_params: dict[int, Any] | None = None,
requires_materialization: bool = False,
- preferred_object_store_id: Optional[str] = None,
- preferred_outputs_object_store_id: Optional[str] = None,
- preferred_intermediate_object_store_id: Optional[str] = None,
- effective_outputs: Optional[list[EffectiveOutput]] = None,
- on_complete: Optional[list[dict[str, Any]]] = None,
+ preferred_object_store_id: str | None = None,
+ preferred_outputs_object_store_id: str | None = None,
+ preferred_intermediate_object_store_id: str | None = None,
+ effective_outputs: list[EffectiveOutput] | None = None,
+ on_complete: list[dict[str, Any]] | None = None,
) -> None:
self.target_history = target_history
self.replacement_dict = replacement_dict or {}
@@ -266,7 +264,7 @@ def _get_target_history(
trans: "GalaxyWebTransaction",
workflow: "Workflow",
payload: dict[str, Any],
- param_keys: Optional[list[list]] = None,
+ param_keys: list[list] | None = None,
index: int = 0,
) -> History:
param_keys = param_keys or []
@@ -569,7 +567,7 @@ def workflow_run_config_to_request(
if step.type == "subworkflow":
subworkflow = step.subworkflow
assert subworkflow
- effective_outputs: Optional[list[EffectiveOutput]] = None
+ effective_outputs: list[EffectiveOutput] | None = None
if run_config.preferred_intermediate_object_store_id or run_config.preferred_outputs_object_store_id:
step_outputs = step.workflow_outputs
effective_outputs = []
@@ -654,7 +652,7 @@ def workflow_request_to_run_config(
history = workflow_invocation.history
replacement_dict = {}
inputs: dict[
- int, Union[HistoryDatasetAssociation, HistoryDatasetCollectionAssociation, str, int, float, bool, None]
+ int, HistoryDatasetAssociation | HistoryDatasetCollectionAssociation | str | int | float | bool | None
] = {}
param_map = {}
resource_params = {}
diff --git a/lib/galaxy/workflow/scheduling_manager.py b/lib/galaxy/workflow/scheduling_manager.py
index e0d84aedbca..35f50f37b3f 100644
--- a/lib/galaxy/workflow/scheduling_manager.py
+++ b/lib/galaxy/workflow/scheduling_manager.py
@@ -5,9 +5,7 @@ from datetime import (
)
from functools import partial
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
)
from sqlalchemy.orm import Session
@@ -185,7 +183,7 @@ class WorkflowSchedulingManager(ConfiguresHandlers):
workflow_invocation: model.WorkflowInvocation,
request_params,
flush: bool = True,
- initial_state: Optional[InvocationState] = None,
+ initial_state: InvocationState | None = None,
):
initial_state = initial_state or model.WorkflowInvocation.states.NEW
workflow_invocation.set_state(initial_state)
@@ -292,7 +290,7 @@ class WorkflowSchedulingManager(ConfiguresHandlers):
log.info("Tag [%s] handlers: %s", tag, ", ".join(handlers))
self.__handlers_configured = True
- def __init_plugin(self, plugin_type: str, workflow_scheduler_id: Union[str, None] = None, **kwds) -> None:
+ def __init_plugin(self, plugin_type: str, workflow_scheduler_id: str | None = None, **kwds) -> None:
workflow_scheduler_id = workflow_scheduler_id or self.default_scheduler_id
if workflow_scheduler_id in self.workflow_schedulers:
@@ -309,7 +307,6 @@ class WorkflowSchedulingManager(ConfiguresHandlers):
class WorkflowRequestMonitor(Monitors):
-
def __init__(self, app: "MinimalManagerApp", workflow_scheduling_manager: WorkflowSchedulingManager) -> None:
self.app = app
self.workflow_scheduling_manager = workflow_scheduling_manager
diff --git a/lib/galaxy/workflow/workflow_parameter_input_definitions.py b/lib/galaxy/workflow/workflow_parameter_input_definitions.py
index 5b3b9f170e5..60602188fa1 100644
--- a/lib/galaxy/workflow/workflow_parameter_input_definitions.py
+++ b/lib/galaxy/workflow/workflow_parameter_input_definitions.py
@@ -1,6 +1,5 @@
from typing import (
Literal,
- Union,
)
from galaxy.tools.parameters.basic import (
@@ -13,15 +12,15 @@ from galaxy.tools.parameters.basic import (
)
INPUT_PARAMETER_TYPES = Literal["text", "integer", "float", "boolean", "color", "directory_uri"]
-default_source_type = dict[str, Union[int, float, bool, str]]
-tool_param_type = Union[
- TextToolParameter,
- IntegerToolParameter,
- FloatToolParameter,
- BooleanToolParameter,
- ColorToolParameter,
- DirectoryUriToolParameter,
-]
+default_source_type = dict[str, int | float | bool | str]
+tool_param_type = (
+ TextToolParameter
+ | IntegerToolParameter
+ | FloatToolParameter
+ | BooleanToolParameter
+ | ColorToolParameter
+ | DirectoryUriToolParameter
+)
def get_default_parameter(param_type: INPUT_PARAMETER_TYPES) -> tool_param_type:
diff --git a/lib/galaxy_test/api/_framework.py b/lib/galaxy_test/api/_framework.py
index 3668418a705..a5509e79155 100644
--- a/lib/galaxy_test/api/_framework.py
+++ b/lib/galaxy_test/api/_framework.py
@@ -1,7 +1,4 @@
from collections.abc import Iterator
-from typing import (
- Optional,
-)
from unittest import SkipTest
import pytest
@@ -22,7 +19,7 @@ except ImportError:
class ApiTestCase(FunctionalTestCase, UsesApiTestCaseMixin, UsesCeleryTasks):
galaxy_driver_class = GalaxyTestDriver
- _test_driver: Optional[GalaxyTestDriver]
+ _test_driver: GalaxyTestDriver | None
def setUp(self):
super().setUp()
diff --git a/lib/galaxy_test/api/conftest.py b/lib/galaxy_test/api/conftest.py
index 17c8f19026b..2ab72d14bae 100644
--- a/lib/galaxy_test/api/conftest.py
+++ b/lib/galaxy_test/api/conftest.py
@@ -5,7 +5,6 @@ from collections.abc import Iterator
from dataclasses import dataclass
from typing import (
Any,
- Optional,
)
import pytest
@@ -40,10 +39,10 @@ from galaxy_test.base.testcase import host_port_and_url
@dataclass
class ApiConfigObject:
host: str
- port: Optional[str]
+ port: str | None
url: str
- user_api_key: Optional[str]
- admin_api_key: Optional[str]
+ user_api_key: str | None
+ admin_api_key: str | None
test_data_resolver: Any
keepOutdir: Any
diff --git a/lib/galaxy_test/api/test_display_applications.py b/lib/galaxy_test/api/test_display_applications.py
index c02195c8dc6..458551aa6d9 100644
--- a/lib/galaxy_test/api/test_display_applications.py
+++ b/lib/galaxy_test/api/test_display_applications.py
@@ -1,6 +1,5 @@
import random
import time
-from typing import Optional
from galaxy.util import UNKNOWN
from galaxy_test.base.decorators import requires_admin
@@ -60,7 +59,7 @@ class TestDisplayApplicationsApi(ApiTestCase):
self._assert_status_code_is(response, 403)
def test_create_link(self):
- cases: list[dict[str, Optional[str]]] = [
+ cases: list[dict[str, str | None]] = [
{"file": "1.interval", "app": "igv_interval_as_bed", "step": "bed_file"},
{"file": "1.bam", "app": "igv_bam", "step": None},
{"file": "test.vcf", "app": "igv_vcf", "step": "bgzip_file"},
diff --git a/lib/galaxy_test/api/test_exports.py b/lib/galaxy_test/api/test_exports.py
index f120abe1b74..9d1d5cf16bd 100644
--- a/lib/galaxy_test/api/test_exports.py
+++ b/lib/galaxy_test/api/test_exports.py
@@ -5,8 +5,6 @@ These tests verify:
- Export records are properly created when exporting
"""
-from typing import Optional
-
from galaxy_test.base.api import UsesCeleryTasks
from galaxy_test.base.populators import (
DatasetPopulator,
@@ -27,7 +25,7 @@ class TestExportsEndpoint(ApiTestCase, UsesCeleryTasks):
self.dataset_populator = DatasetPopulator(self.galaxy_interactor)
self.workflow_populator = WorkflowPopulator(self.galaxy_interactor)
- def _find_export_by_object_id(self, exports: list, object_id: str) -> Optional[dict]:
+ def _find_export_by_object_id(self, exports: list, object_id: str) -> dict | None:
"""Find an export record by its object_id in the metadata."""
for export in exports:
metadata = export.get("export_metadata", {})
diff --git a/lib/galaxy_test/api/test_folder_contents.py b/lib/galaxy_test/api/test_folder_contents.py
index c491102ab66..23ce25f7810 100644
--- a/lib/galaxy_test/api/test_folder_contents.py
+++ b/lib/galaxy_test/api/test_folder_contents.py
@@ -1,6 +1,5 @@
from typing import (
Any,
- Optional,
)
from galaxy_test.base.decorators import requires_new_library
@@ -336,7 +335,7 @@ class TestFolderContentsApi(ApiTestCase):
assert item["name"] == expected_order_by_name[index]
def _assert_index_count_is_correct(
- self, raw_response, expected_contents_count: int, expected_total_count: Optional[int] = None
+ self, raw_response, expected_contents_count: int, expected_total_count: int | None = None
) -> dict:
self._assert_status_code_is(raw_response, 200)
if expected_total_count is None:
@@ -352,9 +351,7 @@ class TestFolderContentsApi(ApiTestCase):
root_folder_id = self.library["root_folder_id"]
return self._create_subfolder_in(root_folder_id, name)
- def _create_subfolder_in(
- self, folder_id: str, name: Optional[str] = None, description: Optional[str] = None
- ) -> str:
+ def _create_subfolder_in(self, folder_id: str, name: str | None = None, description: str | None = None) -> str:
data = {
"name": name or "Test Folder",
"description": description or f"The description of {name}",
@@ -368,9 +365,9 @@ class TestFolderContentsApi(ApiTestCase):
self,
history_id: str,
folder_id: str,
- name: Optional[str] = None,
- content: Optional[str] = None,
- ldda_message: Optional[str] = None,
+ name: str | None = None,
+ content: str | None = None,
+ ldda_message: str | None = None,
**kwds,
) -> tuple[str, str]:
"""Returns a tuple with the LDDA ID and the underlying HDA ID"""
@@ -387,7 +384,7 @@ class TestFolderContentsApi(ApiTestCase):
self._assert_status_code_is(create_response, 200)
return create_response.json()
- def _create_hda(self, history_id: str, name: Optional[str] = None, content: Optional[str] = None, **kwds) -> str:
+ def _create_hda(self, history_id: str, name: str | None = None, content: str | None = None, **kwds) -> str:
hda = self.dataset_populator.new_dataset(history_id, name=name, content=content, **kwds)
hda_id = hda["id"]
return hda_id
diff --git a/lib/galaxy_test/api/test_group_roles.py b/lib/galaxy_test/api/test_group_roles.py
index 728fe4884da..c0f9c8f9510 100644
--- a/lib/galaxy_test/api/test_group_roles.py
+++ b/lib/galaxy_test/api/test_group_roles.py
@@ -1,7 +1,3 @@
-from typing import (
- Optional,
-)
-
from galaxy_test.api._framework import ApiTestCase
from galaxy_test.base.decorators import (
requires_admin,
@@ -18,7 +14,7 @@ class TestGroupRolesApi(ApiTestCase):
self.dataset_populator = DatasetPopulator(self.galaxy_interactor)
@requires_admin
- def test_index(self, group_name: Optional[str] = None):
+ def test_index(self, group_name: str | None = None):
group_name = group_name or "test-group_roles"
group = self._create_group(group_name)
encoded_group_id = group["id"]
@@ -125,7 +121,7 @@ class TestGroupRolesApi(ApiTestCase):
delete_response = self._delete(f"groups/{encoded_group_id}/roles/{encoded_role_id}", admin=True)
self._assert_status_code_is(delete_response, 400)
- def _create_group(self, group_name: str, encoded_role_ids: Optional[list[str]] = None):
+ def _create_group(self, group_name: str, encoded_role_ids: list[str] | None = None):
if encoded_role_ids is None:
encoded_role_ids = [self.dataset_populator.user_private_role_id()]
role_ids = encoded_role_ids
diff --git a/lib/galaxy_test/api/test_group_users.py b/lib/galaxy_test/api/test_group_users.py
index c1deee8d252..9ae59362422 100644
--- a/lib/galaxy_test/api/test_group_users.py
+++ b/lib/galaxy_test/api/test_group_users.py
@@ -1,7 +1,3 @@
-from typing import (
- Optional,
-)
-
from galaxy_test.api._framework import ApiTestCase
from galaxy_test.base.decorators import (
requires_admin,
@@ -18,7 +14,7 @@ class TestGroupUsersApi(ApiTestCase):
self.dataset_populator = DatasetPopulator(self.galaxy_interactor)
@requires_admin
- def test_index(self, group_name: Optional[str] = None):
+ def test_index(self, group_name: str | None = None):
group_name = group_name or "test-group_users"
group = self._create_group(group_name)
encoded_group_id = group["id"]
@@ -124,7 +120,7 @@ class TestGroupUsersApi(ApiTestCase):
delete_response = self._delete(f"groups/{encoded_group_id}/users/{encoded_user_id}", admin=True)
self._assert_status_code_is(delete_response, 400)
- def _create_group(self, group_name: str, encoded_user_ids: Optional[list[str]] = None):
+ def _create_group(self, group_name: str, encoded_user_ids: list[str] | None = None):
if encoded_user_ids is None:
encoded_user_ids = [self.dataset_populator.user_id()]
user_ids = encoded_user_ids
diff --git a/lib/galaxy_test/api/test_groups.py b/lib/galaxy_test/api/test_groups.py
index fafe689dfe2..12dd61f8cba 100644
--- a/lib/galaxy_test/api/test_groups.py
+++ b/lib/galaxy_test/api/test_groups.py
@@ -1,7 +1,3 @@
-from typing import (
- Optional,
-)
-
from galaxy_test.base.populators import DatasetPopulator
from ._framework import ApiTestCase
@@ -13,7 +9,7 @@ class TestGroupsApi(ApiTestCase):
super().setUp()
self.dataset_populator = DatasetPopulator(self.galaxy_interactor)
- def _create_valid_group(self, group_name: Optional[str] = None):
+ def _create_valid_group(self, group_name: str | None = None):
payload = self._build_valid_group_payload(group_name)
response = self._post("groups", payload, admin=True, json=True)
self._assert_status_code_is(response, 200)
@@ -249,7 +245,7 @@ class TestGroupsApi(ApiTestCase):
for role in roles:
assert role["id"] in role_ids
- def _build_valid_group_payload(self, name: Optional[str] = None):
+ def _build_valid_group_payload(self, name: str | None = None):
name = name or self.dataset_populator.get_random_name()
user_id = self.dataset_populator.user_id()
role_id = self.dataset_populator.user_private_role_id()
diff --git a/lib/galaxy_test/api/test_history_contents.py b/lib/galaxy_test/api/test_history_contents.py
index dd0f929cc32..8d6927a9a90 100644
--- a/lib/galaxy_test/api/test_history_contents.py
+++ b/lib/galaxy_test/api/test_history_contents.py
@@ -1,8 +1,6 @@
import urllib.parse
from typing import (
Any,
- Optional,
- Union,
)
from galaxy_test.api._framework import ApiTestCase
@@ -336,8 +334,8 @@ class TestHistoryContentsApi(ApiTestCase):
history_id: str,
content_id: str,
item_type: str,
- expected_view: Optional[str] = None,
- expected_keys: Optional[list[str]] = None,
+ expected_view: str | None = None,
+ expected_keys: list[str] | None = None,
):
view = f"&view={expected_view}" if expected_view else ""
keys = f"&keys={','.join(expected_keys)}" if expected_keys else ""
@@ -480,7 +478,7 @@ class TestHistoryContentsApi(ApiTestCase):
hda = self.dataset_populator.get_history_dataset_details(history_id=history_id, content_id=dataset["id"])
assert hda["name"] != dataset["name"]
with self._different_user():
- exception: Union[Exception, None] = None
+ exception: Exception | None = None
try:
self.dataset_populator.rename_dataset(dataset["id"])
except AssertionError as e:
@@ -498,7 +496,7 @@ class TestHistoryContentsApi(ApiTestCase):
)
assert hdca["name"] != dataset_collection["name"]
with self._different_user():
- exception: Union[Exception, None] = None
+ exception: Exception | None = None
try:
self.dataset_populator.rename_collection(dataset_collection_id)
except AssertionError as e:
@@ -1813,15 +1811,15 @@ class TestHistoryContentsApiBulkOperation(ApiTestCase):
def _get_hidden_items_from_history_contents(self, history_contents) -> list[Any]:
return [content for content in history_contents if not content["visible"]]
- def _get_collection_with_id_from_history_contents(self, history_contents, collection_id: str) -> Optional[Any]:
+ def _get_collection_with_id_from_history_contents(self, history_contents, collection_id: str) -> Any | None:
return self._get_item_with_id_from_history_contents(history_contents, "dataset_collection", collection_id)
- def _get_dataset_with_id_from_history_contents(self, history_contents, dataset_id: str) -> Optional[Any]:
+ def _get_dataset_with_id_from_history_contents(self, history_contents, dataset_id: str) -> Any | None:
return self._get_item_with_id_from_history_contents(history_contents, "dataset", dataset_id)
def _get_item_with_id_from_history_contents(
self, history_contents, history_content_type: str, dataset_id: str
- ) -> Optional[Any]:
+ ) -> Any | None:
for item in history_contents:
if item["history_content_type"] == history_content_type and item["id"] == dataset_id:
return item
diff --git a/lib/galaxy_test/api/test_jobs.py b/lib/galaxy_test/api/test_jobs.py
index 4f35aff357d..963037f7955 100644
--- a/lib/galaxy_test/api/test_jobs.py
+++ b/lib/galaxy_test/api/test_jobs.py
@@ -3,7 +3,6 @@ import json
import os
import time
from operator import itemgetter
-from typing import Union
from unittest import SkipTest
import requests
@@ -1268,8 +1267,8 @@ steps:
return tool_response
def _search_payload(
- self, tool_id: str, inputs: str, state: str = "ok", history_id: Union[str, None] = None
- ) -> dict[str, Union[str, None]]:
+ self, tool_id: str, inputs: str, state: str = "ok", history_id: str | None = None
+ ) -> dict[str, str | None]:
search_payload = dict(tool_id=tool_id, inputs=inputs, history_id=history_id, state=state)
return search_payload
diff --git a/lib/galaxy_test/api/test_pages.py b/lib/galaxy_test/api/test_pages.py
index 077fbe9a305..a8e43304857 100644
--- a/lib/galaxy_test/api/test_pages.py
+++ b/lib/galaxy_test/api/test_pages.py
@@ -1,7 +1,5 @@
from typing import (
Any,
- Optional,
- Union,
)
from unittest import SkipTest
from uuid import uuid4
@@ -604,21 +602,19 @@ steps:
response = self._put(f"pages/{page_id}/share_with_users", data, json=True)
api_asserts.assert_status_code_is_ok(response)
- def _index_raw(self, params: Optional[dict[str, Any]] = None) -> Response:
+ def _index_raw(self, params: dict[str, Any] | None = None) -> Response:
index_response = self._get("pages", data=params or {})
return index_response
- def _index(self, params: Optional[dict[str, Any]] = None) -> list[dict[str, Any]]:
+ def _index(self, params: dict[str, Any] | None = None) -> list[dict[str, Any]]:
index_response = self._index_raw(params)
self._assert_status_code_is(index_response, 200)
return index_response.json()
- def _index_ids(self, params: Optional[dict[str, Any]] = None) -> list[dict[str, Any]]:
+ def _index_ids(self, params: dict[str, Any] | None = None) -> list[dict[str, Any]]:
return [p["id"] for p in self._index(params)]
- def _users_index_has_page_with_id(
- self, has_id: Union[dict[str, Any], str], params: Optional[dict[str, Any]] = None
- ):
+ def _users_index_has_page_with_id(self, has_id: dict[str, Any] | str, params: dict[str, Any] | None = None):
pages = self._index(params)
if isinstance(has_id, dict):
target_id = has_id["id"]
diff --git a/lib/galaxy_test/api/test_roles.py b/lib/galaxy_test/api/test_roles.py
index 33d1e6b3a69..80a80c6c7eb 100644
--- a/lib/galaxy_test/api/test_roles.py
+++ b/lib/galaxy_test/api/test_roles.py
@@ -1,6 +1,5 @@
from typing import (
Any,
- Optional,
)
from galaxy.exceptions import error_codes
@@ -221,7 +220,7 @@ class TestRolesApi(ApiTestCase):
response = self._post("roles", payload, admin=True, json=True)
self._assert_status_code_is(response, 200)
- def _create_role(self, name: Optional[str] = None, description: Optional[str] = None) -> dict[str, Any]:
+ def _create_role(self, name: str | None = None, description: str | None = None) -> dict[str, Any]:
payload = self._build_valid_role_payload(name=name, description=description)
response = self._post("roles", payload, admin=True, json=True)
assert_status_code_is(response, 200)
@@ -229,7 +228,7 @@ class TestRolesApi(ApiTestCase):
self.check_role_dict(role)
return role
- def _build_valid_role_payload(self, name: Optional[str] = None, description: Optional[str] = None):
+ def _build_valid_role_payload(self, name: str | None = None, description: str | None = None):
name = name or self.dataset_populator.get_random_name()
description = description or f"A test role with name: {name}."
payload = {
@@ -240,7 +239,7 @@ class TestRolesApi(ApiTestCase):
return payload
@staticmethod
- def check_role_dict(role_dict: dict[str, Any], assert_id: Optional[str] = None) -> None:
+ def check_role_dict(role_dict: dict[str, Any], assert_id: str | None = None) -> None:
assert_has_keys(role_dict, "id", "name", "model_class", "url")
assert role_dict["model_class"] == "Role"
if assert_id is not None:
diff --git a/lib/galaxy_test/api/test_tools.py b/lib/galaxy_test/api/test_tools.py
index 0f0085e39c0..f6f5eca28de 100644
--- a/lib/galaxy_test/api/test_tools.py
+++ b/lib/galaxy_test/api/test_tools.py
@@ -7,7 +7,6 @@ from io import BytesIO
from typing import (
Any,
Literal,
- Optional,
)
from uuid import uuid4
@@ -553,7 +552,7 @@ class TestToolsApi(ApiTestCase, TestsTools):
tool_id: str,
history_id: str,
*,
- options_pagination: Optional[dict[str, Any]] = None,
+ options_pagination: dict[str, Any] | None = None,
param_name: str = "f1",
) -> dict[str, Any]:
"""POST ``tools/{tool_id}/build`` and return the named input dict."""
@@ -4032,7 +4031,7 @@ class TestToolsApi(ApiTestCase, TestsTools):
# assert "User does not have permission to use a dataset" in err_message, err_message
@contextlib.contextmanager
- def _different_user_and_history(self, user_email: Optional[str] = None):
+ def _different_user_and_history(self, user_email: str | None = None):
with self._different_user(email=user_email):
with self.dataset_populator.test_history() as other_history_id:
yield other_history_id
diff --git a/lib/galaxy_test/api/test_unprivileged_tools.py b/lib/galaxy_test/api/test_unprivileged_tools.py
index f0de1ae403f..6b3e8038906 100644
--- a/lib/galaxy_test/api/test_unprivileged_tools.py
+++ b/lib/galaxy_test/api/test_unprivileged_tools.py
@@ -12,7 +12,6 @@ from .test_tools import TestsTools
class TestUnprivilegedToolsApi(ApiTestCase, TestsTools):
-
def setUp(self):
super().setUp()
self.dataset_populator = DatasetPopulator(self.galaxy_interactor)
diff --git a/lib/galaxy_test/api/test_users.py b/lib/galaxy_test/api/test_users.py
index 3787a9c1394..cb3af551de4 100644
--- a/lib/galaxy_test/api/test_users.py
+++ b/lib/galaxy_test/api/test_users.py
@@ -23,7 +23,6 @@ TEST_USER_EMAIL_SHOW = "user_for_show_test@bx.psu.edu"
class TestUsersApi(ApiTestCase):
-
@requires_admin
@requires_new_user
def test_index(self):
diff --git a/lib/galaxy_test/api/test_wes.py b/lib/galaxy_test/api/test_wes.py
index 7ded9b0621e..82ccd133357 100644
--- a/lib/galaxy_test/api/test_wes.py
+++ b/lib/galaxy_test/api/test_wes.py
@@ -5,7 +5,6 @@ import io
import json
from typing import (
Any,
- Optional,
)
from urllib.parse import urljoin
from uuid import uuid4
@@ -758,8 +757,8 @@ steps:
def _wes_post(
self,
endpoint: str,
- data: Optional[dict[str, Any]] = None,
- files: Optional[dict[str, Any]] = None,
+ data: dict[str, Any] | None = None,
+ files: dict[str, Any] | None = None,
authenticated: bool = True,
) -> requests.Response:
"""Make POST request to WES API endpoint.
@@ -776,7 +775,7 @@ steps:
def _wes_get(
self,
endpoint: str,
- params: Optional[dict[str, Any]] = None,
+ params: dict[str, Any] | None = None,
authenticated: bool = True,
) -> requests.Response:
"""Make GET request to WES API endpoint.
@@ -791,11 +790,11 @@ steps:
def _submit_wes_workflow(
self,
- workflow_content: Optional[str] = None,
+ workflow_content: str | None = None,
workflow_type: str = "gx_workflow_ga",
workflow_type_version: str = "v1",
- engine_parameters: Optional[dict[str, Any]] = None,
- history_id: Optional[str] = None,
+ engine_parameters: dict[str, Any] | None = None,
+ history_id: str | None = None,
**workflow_inputs: Any,
) -> requests.Response:
"""Helper to submit WES workflow with standard setup.
@@ -843,11 +842,11 @@ steps:
def _submit_wes_workflow_and_get_invocation_id(
self,
- workflow_content: Optional[str] = None,
+ workflow_content: str | None = None,
workflow_type: str = "gx_workflow_ga",
workflow_type_version: str = "v1",
- engine_parameters: Optional[dict[str, Any]] = None,
- history_id: Optional[str] = None,
+ engine_parameters: dict[str, Any] | None = None,
+ history_id: str | None = None,
**workflow_inputs: Any,
) -> str:
response = self._submit_wes_workflow(
diff --git a/lib/galaxy_test/api/test_workflow_build_module.py b/lib/galaxy_test/api/test_workflow_build_module.py
index 546f6192e39..db06d416c00 100644
--- a/lib/galaxy_test/api/test_workflow_build_module.py
+++ b/lib/galaxy_test/api/test_workflow_build_module.py
@@ -6,7 +6,6 @@ from ._framework import ApiTestCase
class TestBuildWorkflowModule(ApiTestCase):
-
def setUp(self):
super().setUp()
self.workflow_populator = WorkflowPopulator(self.galaxy_interactor)
diff --git a/lib/galaxy_test/api/test_workflow_extraction.py b/lib/galaxy_test/api/test_workflow_extraction.py
index 17d6c0a99c9..86470f10d8c 100644
--- a/lib/galaxy_test/api/test_workflow_extraction.py
+++ b/lib/galaxy_test/api/test_workflow_extraction.py
@@ -11,7 +11,6 @@ from json import (
)
from typing import (
Any,
- Optional,
TYPE_CHECKING,
)
@@ -52,7 +51,7 @@ class _ExtractionHelpersMixin:
def _assert_status_code_is(self, response: "Response", expected_status_code: int) -> None: ...
def assert_steps_of_type(
- self, workflow: dict[str, Any], step_type: str, expected_len: Optional[int] = None
+ self, workflow: dict[str, Any], step_type: str, expected_len: int | None = None
) -> list[dict[str, Any]]: ...
def _setup_extract_dataset_then_cat(self, history_id):
diff --git a/lib/galaxy_test/api/test_workflows.py b/lib/galaxy_test/api/test_workflows.py
index ed002f7d638..4490c92416d 100644
--- a/lib/galaxy_test/api/test_workflows.py
+++ b/lib/galaxy_test/api/test_workflows.py
@@ -10,8 +10,6 @@ from tempfile import mkdtemp
from typing import (
Any,
cast,
- Optional,
- Union,
)
from uuid import uuid4
@@ -205,23 +203,23 @@ class BaseWorkflowsApiTestCase(ApiTestCase, RunsWorkflowFixtures):
def _setup_workflow_run(
self,
- workflow: Optional[dict[str, Any]] = None,
+ workflow: dict[str, Any] | None = None,
inputs_by: str = "step_id",
- history_id: Optional[str] = None,
- workflow_id: Optional[str] = None,
+ history_id: str | None = None,
+ workflow_id: str | None = None,
) -> tuple[dict[str, Any], str, str]:
return self.workflow_populator.setup_workflow_run(workflow, inputs_by, history_id, workflow_id)
def _ds_entry(self, history_content):
return self.dataset_populator.ds_entry(history_content)
- def _invocation_details(self, workflow_id: Optional[str], invocation_id: str, **kwds):
+ def _invocation_details(self, workflow_id: str | None, invocation_id: str, **kwds):
invocation_details_response = self._get(f"invocations/{invocation_id}", data=kwds)
self._assert_status_code_is(invocation_details_response, 200)
invocation_details = invocation_details_response.json()
return invocation_details
- def _run_jobs(self, has_workflow, history_id: str, **kwds) -> Union[dict[str, Any], RunJobsSummary]:
+ def _run_jobs(self, has_workflow, history_id: str, **kwds) -> dict[str, Any] | RunJobsSummary:
return self.workflow_populator.run_workflow(has_workflow, history_id=history_id, **kwds)
def _run_workflow(self, has_workflow, history_id: str, **kwds) -> RunJobsSummary:
@@ -260,7 +258,7 @@ class BaseWorkflowsApiTestCase(ApiTestCase, RunsWorkflowFixtures):
self._assert_status_code_is(show_response, 200)
return show_response.json()
- def _latest_instance_id(self, workflow_id: str, history_id: Optional[str] = None) -> str:
+ def _latest_instance_id(self, workflow_id: str, history_id: str | None = None) -> str:
# Get latest version, to get latest instance id and confirm the name has changed
latest_download = self._download_workflow(workflow_id, style="run", history_id=history_id)
latest_instance_id = latest_download["workflow_id"]
@@ -2606,7 +2604,7 @@ steps:
in reverse_content
)
- def __run_cat_workflow(self, inputs_by, history_id: Optional[str] = None):
+ def __run_cat_workflow(self, inputs_by, history_id: str | None = None):
workflow = self.workflow_populator.load_workflow(name="test_for_run")
workflow["steps"]["0"]["uuid"] = str(uuid4())
workflow["steps"]["1"]["uuid"] = str(uuid4())
diff --git a/lib/galaxy_test/base/api.py b/lib/galaxy_test/base/api.py
index da0f014d1e4..ef55c58b41c 100644
--- a/lib/galaxy_test/base/api.py
+++ b/lib/galaxy_test/base/api.py
@@ -53,7 +53,7 @@ class UsesCeleryTasks:
@classmethod
def handle_galaxy_config_kwds(cls, config: dict[str, Any]) -> None:
config["enable_celery_tasks"] = True
- config["metadata_strategy"] = f'{config.get("metadata_strategy", "directory")}_celery'
+ config["metadata_strategy"] = f"{config.get('metadata_strategy', 'directory')}_celery"
celery_conf: dict[str, Any] = config.get("celery_conf", {})
celery_conf.update(DEFAULT_CELERY_CONFIG)
config["celery_conf"] = celery_conf
@@ -153,7 +153,7 @@ class UsesApiTestCaseMixin:
return user, self._post(f"users/{user['id']}/api_key", admin=True).json()
@contextmanager
- def _different_user(self, email: Optional[str] = None, anon=False):
+ def _different_user(self, email: str | None = None, anon=False):
"""Use in test cases to switch get/post operations to act as new user
..code-block:: python
@@ -304,7 +304,5 @@ class AnonymousGalaxyInteractor(ApiTestInteractor):
def __init__(self, test_case):
super().__init__(test_case)
- def _get_user_key(
- self, user_key: Optional[str], admin_key: Optional[str], test_user: Optional[str] = None
- ) -> Optional[str]:
+ def _get_user_key(self, user_key: str | None, admin_key: str | None, test_user: str | None = None) -> str | None:
return None
diff --git a/lib/galaxy_test/base/api_asserts.py b/lib/galaxy_test/base/api_asserts.py
index 6d5cdfc28b4..60108d540ff 100644
--- a/lib/galaxy_test/base/api_asserts.py
+++ b/lib/galaxy_test/base/api_asserts.py
@@ -3,8 +3,6 @@
from typing import (
Any,
cast,
- Optional,
- Union,
)
from requests import Response
@@ -12,14 +10,14 @@ from requests import Response
from galaxy.exceptions.error_codes import ErrorCode
-def assert_status_code_is(response: Response, expected_status_code: int, failure_message: Optional[str] = None):
+def assert_status_code_is(response: Response, expected_status_code: int, failure_message: str | None = None):
"""Assert that the supplied response has the expect status code."""
response_status_code = response.status_code
if expected_status_code != response_status_code:
_report_status_code_error(response, expected_status_code, failure_message)
-def assert_status_code_is_ok(response: Response, failure_message: Optional[str] = None):
+def assert_status_code_is_ok(response: Response, failure_message: str | None = None):
"""Assert that the supplied response is okay.
This is an alternative to ``response.raise_for_status()`` with a more detailed
@@ -33,7 +31,7 @@ def assert_status_code_is_ok(response: Response, failure_message: Optional[str]
_report_status_code_error(response, "2XX", failure_message)
-def assert_status_code_is_not_ok(response: Response, failure_message: Optional[str] = None):
+def assert_status_code_is_not_ok(response: Response, failure_message: str | None = None):
"""Assert that the supplied response is not okay.
.. seealso:: :py:meth:`assert_status_code_is_ok`
@@ -44,9 +42,7 @@ def assert_status_code_is_not_ok(response: Response, failure_message: Optional[s
_report_status_code_error(response, "2XX", failure_message)
-def _report_status_code_error(
- response: Response, expected_status_code: Union[str, int], failure_message: Optional[str]
-):
+def _report_status_code_error(response: Response, expected_status_code: str | int, failure_message: str | None):
try:
body = response.json()
except Exception:
@@ -71,7 +67,7 @@ def assert_not_has_keys(response: dict, *keys: str):
assert key not in response, f"Response [{response}] contains invalid key [{key}]"
-def assert_error_code_is(response: Union[Response, dict], error_code: Union[int, ErrorCode]):
+def assert_error_code_is(response: Response | dict, error_code: int | ErrorCode):
"""Assert that the supplied response has the supplied Galaxy error code.
Galaxy error codes can be imported from :py:mod:`galaxy.exceptions.error_codes`
@@ -95,14 +91,14 @@ def assert_object_id_error(response: Response):
assert_error_code_is(response, 404001)
-def assert_error_message_contains(response: Union[Response, dict], expected_contains: str):
+def assert_error_message_contains(response: Response | dict, expected_contains: str):
as_dict = _as_dict(response)
assert_has_keys(as_dict, "err_msg")
err_msg = as_dict["err_msg"]
assert expected_contains in err_msg, f"Expected error message [{err_msg}] to contain [{expected_contains}]."
-def _as_dict(response: Union[Response, dict]) -> dict[str, Any]:
+def _as_dict(response: Response | dict) -> dict[str, Any]:
as_dict: dict[str, Any]
if isinstance(response, Response):
as_dict = cast(dict, response.json())
diff --git a/lib/galaxy_test/base/api_util.py b/lib/galaxy_test/base/api_util.py
index c6a5552926e..0cb122c4339 100644
--- a/lib/galaxy_test/base/api_util.py
+++ b/lib/galaxy_test/base/api_util.py
@@ -2,9 +2,6 @@ import base64
import os
import random
import string
-from typing import (
- Optional,
-)
DEFAULT_GALAXY_MASTER_API_KEY = "TEST123"
DEFAULT_GALAXY_USER_API_KEY = None
@@ -31,7 +28,7 @@ def get_admin_api_key() -> str:
return DEFAULT_GALAXY_MASTER_API_KEY
-def get_user_api_key() -> Optional[str]:
+def get_user_api_key() -> str | None:
"""Test user API key to use for functional tests.
If set, this should drive API based testing - if not set an admin API key will
@@ -49,7 +46,7 @@ def baseauth_headers(username: str, password: str) -> dict[str, str]:
return headers
-def random_name(prefix: Optional[str] = None, suffix: Optional[str] = None, len: int = 10) -> str:
+def random_name(prefix: str | None = None, suffix: str | None = None, len: int = 10) -> str:
return "{}{}{}".format(
prefix or "",
"".join(random.choice(string.ascii_lowercase + string.digits) for _ in range(len)),
diff --git a/lib/galaxy_test/base/decorators.py b/lib/galaxy_test/base/decorators.py
index 1bf4555014c..7b7e5216549 100644
--- a/lib/galaxy_test/base/decorators.py
+++ b/lib/galaxy_test/base/decorators.py
@@ -14,19 +14,18 @@ import unittest
from functools import wraps
from typing import (
Literal,
- Union,
)
import pytest
-KnownRequirementT = Union[
- Literal["admin"],
- Literal["celery"],
- Literal["new_history"],
- Literal["new_library"],
- Literal["new_published_objects"],
- Literal["new_user"],
-]
+KnownRequirementT = (
+ Literal["admin"]
+ | Literal["celery"]
+ | Literal["new_history"]
+ | Literal["new_library"]
+ | Literal["new_published_objects"]
+ | Literal["new_user"]
+)
def has_requirement(method, tag: KnownRequirementT):
diff --git a/lib/galaxy_test/base/env.py b/lib/galaxy_test/base/env.py
index a116c22b0e6..f243580a9e4 100644
--- a/lib/galaxy_test/base/env.py
+++ b/lib/galaxy_test/base/env.py
@@ -4,16 +4,13 @@ import fcntl
import os
import socket
import struct
-from typing import (
- Optional,
-)
from galaxy.util import asbool
DEFAULT_WEB_HOST = socket.gethostbyname("localhost")
REQUIRE_ALL_NEEDED_TOOLS = asbool(os.environ.get("GALAXY_TEST_REQUIRE_ALL_NEEDED_TOOLS", "0"))
-GalaxyTarget = tuple[str, Optional[str], str]
+GalaxyTarget = tuple[str, str | None, str]
def setup_keep_outdir() -> str:
diff --git a/lib/galaxy_test/base/mock_http_server.py b/lib/galaxy_test/base/mock_http_server.py
index 7dd6b2bd086..6ac288d4785 100644
--- a/lib/galaxy_test/base/mock_http_server.py
+++ b/lib/galaxy_test/base/mock_http_server.py
@@ -21,7 +21,6 @@ from http.server import (
HTTPServer,
)
from pathlib import Path
-from typing import Optional
from urllib.parse import urlparse
import pytest
@@ -119,8 +118,8 @@ class MockHttpServer:
def __init__(
self,
- base_url: Optional[str],
- handler_class: Optional[type[MockHTTPRequestHandler]],
+ base_url: str | None,
+ handler_class: type[MockHTTPRequestHandler] | None,
is_remote: bool,
):
self.base_url = base_url
@@ -134,10 +133,10 @@ class MockHttpServer:
remote_url: str,
status: int = 200,
body: str | bytes = "",
- file_path: Optional[str] = None,
+ file_path: str | None = None,
content_type: str = "application/octet-stream",
sleep_ms: int = 0,
- response_headers: Optional[dict[str, str]] = None,
+ response_headers: dict[str, str] | None = None,
request_method: str = "GET",
support_head: bool = False,
support_ranges: bool = False,
diff --git a/lib/galaxy_test/base/populators.py b/lib/galaxy_test/base/populators.py
index c631edcf0d1..33ccb0fbfff 100644
--- a/lib/galaxy_test/base/populators.py
+++ b/lib/galaxy_test/base/populators.py
@@ -64,7 +64,6 @@ from typing import (
cast,
Literal,
NamedTuple,
- Optional,
Union,
)
from uuid import UUID
@@ -578,7 +577,7 @@ class BaseDatasetPopulator(BasePopulator):
payload: dict,
assert_ok: bool = True,
timeout: timeout_type = DEFAULT_TIMEOUT,
- wait: Optional[bool] = None,
+ wait: bool | None = None,
):
tool_response = self._post("tools/fetch", data=payload, json=True)
if wait is None:
@@ -615,7 +614,7 @@ class BaseDatasetPopulator(BasePopulator):
assert len(hdas) == 1
return hdas[0]
- def create_deferred_hda(self, history_id: str, uri: str, ext: Optional[str] = None) -> dict[str, Any]:
+ def create_deferred_hda(self, history_id: str, uri: str, ext: str | None = None) -> dict[str, Any]:
item = {
"src": "url",
"url": uri,
@@ -671,9 +670,9 @@ class BaseDatasetPopulator(BasePopulator):
def create_from_store(
self,
- store_dict: Optional[dict[str, Any]] = None,
- store_path: Optional[str] = None,
- model_store_format: Optional[str] = None,
+ store_dict: dict[str, Any] | None = None,
+ store_path: str | None = None,
+ model_store_format: str | None = None,
) -> dict[str, Any]:
payload = _store_payload(store_dict=store_dict, store_path=store_path, model_store_format=model_store_format)
create_response = self.create_from_store_raw(payload)
@@ -682,9 +681,9 @@ class BaseDatasetPopulator(BasePopulator):
def create_from_store_async(
self,
- store_dict: Optional[dict[str, Any]] = None,
- store_path: Optional[str] = None,
- model_store_format: Optional[str] = None,
+ store_dict: dict[str, Any] | None = None,
+ store_path: str | None = None,
+ model_store_format: str | None = None,
) -> dict[str, Any]:
payload = _store_payload(store_dict=store_dict, store_path=store_path, model_store_format=model_store_format)
create_response = self.create_from_store_raw_async(payload)
@@ -698,9 +697,9 @@ class BaseDatasetPopulator(BasePopulator):
def create_contents_from_store(
self,
history_id: str,
- store_dict: Optional[dict[str, Any]] = None,
- store_path: Optional[str] = None,
- discarded_data: Optional[str] = None,
+ store_dict: dict[str, Any] | None = None,
+ store_path: str | None = None,
+ discarded_data: str | None = None,
) -> list[dict[str, Any]]:
if store_dict is not None:
assert isinstance(store_dict, dict)
@@ -788,7 +787,7 @@ class BaseDatasetPopulator(BasePopulator):
def wait_for_jobs(
self,
- jobs: Union[list[dict], list[str]],
+ jobs: list[dict] | list[str],
assert_ok: bool = False,
timeout: timeout_type = DEFAULT_TIMEOUT,
ok_states=None,
@@ -822,8 +821,8 @@ class BaseDatasetPopulator(BasePopulator):
def compute_hash(
self,
dataset_id: str,
- hash_function: Optional[str] = "MD5",
- extra_files_path: Optional[str] = None,
+ hash_function: str | None = "MD5",
+ extra_files_path: str | None = None,
wait: bool = True,
) -> Response:
data: dict[str, Any] = {}
@@ -922,13 +921,13 @@ class BaseDatasetPopulator(BasePopulator):
def rename_dataset(
self,
content_id: str,
- new_name: Optional[str] = None,
+ new_name: str | None = None,
):
if not new_name:
new_name = self.get_random_name()
return self.update_dataset(content_id, {"name": new_name})
- def rename_collection(self, content_id: str, new_name: Optional[str] = None):
+ def rename_collection(self, content_id: str, new_name: str | None = None):
if not new_name:
new_name = self.get_random_name()
self.update_dataset_collection(content_id, {"name": new_name})
@@ -1067,7 +1066,7 @@ class BaseDatasetPopulator(BasePopulator):
assert response.status_code == 200, response.text
return response.json()
- def create_tool(self, representation, tool_directory: Optional[str] = None) -> dict[str, Any]:
+ def create_tool(self, representation, tool_directory: str | None = None) -> dict[str, Any]:
payload = dict(
representation=representation,
tool_directory=tool_directory,
@@ -1116,7 +1115,7 @@ class BaseDatasetPopulator(BasePopulator):
yield history_id
@contextlib.contextmanager
- def test_history(self, require_new: bool = True, name: Optional[str] = None) -> Generator[str, None, None]:
+ def test_history(self, require_new: bool = True, name: str | None = None) -> Generator[str, None, None]:
with self._test_history(require_new=require_new, cleanup_callback=self._cleanup_history) as history_id:
yield history_id
@@ -1124,8 +1123,8 @@ class BaseDatasetPopulator(BasePopulator):
def _test_history(
self,
require_new: bool = True,
- cleanup_callback: Optional[Callable[[str], None]] = None,
- name: Optional[str] = None,
+ cleanup_callback: Callable[[str], None] | None = None,
+ name: str | None = None,
) -> Generator[str, None, None]:
if name is not None:
kwds = {"name": name}
@@ -1187,7 +1186,7 @@ class BaseDatasetPopulator(BasePopulator):
payload = {"history_id": history_id, "targets": targets, "__files": __files}
return payload
- def upload_payload(self, history_id: str, content: Optional[str] = None, **kwds) -> dict:
+ def upload_payload(self, history_id: str, content: str | None = None, **kwds) -> dict:
name = kwds.get("name", "Test_Dataset")
dbkey = kwds.get("dbkey", "?")
file_type = kwds.get("file_type", "txt")
@@ -1227,7 +1226,7 @@ class BaseDatasetPopulator(BasePopulator):
api_asserts.assert_status_code_is_ok(download_response)
return self._get_response_to_tempfile(download_response)
- def run_tool_payload(self, tool_id: Optional[str], inputs: dict, history_id: str, **kwds) -> dict:
+ def run_tool_payload(self, tool_id: str | None, inputs: dict, history_id: str, **kwds) -> dict:
# Remove files_%d|file_data parameters from inputs dict and attach
# as __files dictionary.
for key, value in list(inputs.items()):
@@ -1241,7 +1240,7 @@ class BaseDatasetPopulator(BasePopulator):
kwds["credentials_context"] = json.dumps(kwds["credentials_context"])
return dict(tool_id=tool_id, inputs=json.dumps(inputs), history_id=history_id, **kwds)
- def build_tool_state(self, tool_id: str, history_id: str, inputs: Optional[dict] = None):
+ def build_tool_state(self, tool_id: str, history_id: str, inputs: dict | None = None):
if inputs is not None:
payload = {"history_id": history_id, "inputs": inputs}
response = self._post(f"tools/{tool_id}/build", data=payload, json=True)
@@ -1250,7 +1249,7 @@ class BaseDatasetPopulator(BasePopulator):
response.raise_for_status()
return response.json()
- def run_tool_raw(self, tool_id: Optional[str], inputs: dict, history_id: str, **kwds) -> Response:
+ def run_tool_raw(self, tool_id: str | None, inputs: dict, history_id: str, **kwds) -> Response:
payload = self.run_tool_payload(tool_id, inputs, history_id, **kwds)
return self.tools_post(payload)
@@ -1311,7 +1310,7 @@ class BaseDatasetPopulator(BasePopulator):
else:
return display_response.content
- def display_chunk(self, dataset_id: str, offset: int = 0, ck_size: Optional[int] = None) -> dict[str, Any]:
+ def display_chunk(self, dataset_id: str, offset: int = 0, ck_size: int | None = None) -> dict[str, Any]:
# use the dataset display API endpoint with the offset parameter to enable chunking
# of the target dataset for certain datatypes
kwds = {
@@ -1341,13 +1340,13 @@ class BaseDatasetPopulator(BasePopulator):
assert isinstance(transform, list)
return {t["action"] for t in transform}
- def get_history_dataset_details(self, history_id: str, keys: Optional[str] = None, **kwds) -> dict[str, Any]:
+ def get_history_dataset_details(self, history_id: str, keys: str | None = None, **kwds) -> dict[str, Any]:
dataset_id = self.__history_content_id(history_id, **kwds)
details_response = self.get_history_dataset_details_raw(history_id, dataset_id, keys=keys)
details_response.raise_for_status()
return details_response.json()
- def get_history_dataset_details_raw(self, history_id: str, dataset_id: str, keys: Optional[str] = None) -> Response:
+ def get_history_dataset_details_raw(self, history_id: str, dataset_id: str, keys: str | None = None) -> Response:
data = None
if keys:
data = {"keys": keys}
@@ -1397,7 +1396,7 @@ class BaseDatasetPopulator(BasePopulator):
return output_details["id"]
def report_job_error_raw(
- self, job_id: str, dataset_id: str, message: str = "", email: Optional[str] = None
+ self, job_id: str, dataset_id: str, message: str = "", email: str | None = None
) -> Response:
url = f"jobs/{job_id}/error"
payload = dict(
@@ -1409,9 +1408,7 @@ class BaseDatasetPopulator(BasePopulator):
report_response = self._post(url, data=payload, json=True)
return report_response
- def report_job_error(
- self, job_id: str, dataset_id: str, message: str = "", email: Optional[str] = None
- ) -> Response:
+ def report_job_error(self, job_id: str, dataset_id: str, message: str = "", email: str | None = None) -> Response:
report_response = self.report_job_error_raw(job_id, dataset_id, message=message, email=email)
api_asserts.assert_status_code_is_ok(report_response)
return report_response.json()
@@ -1556,7 +1553,7 @@ class BaseDatasetPopulator(BasePopulator):
expected_status: int = 200,
offset: int = 0,
limit: int = 50,
- search: Optional[str] = None,
+ search: str | None = None,
) -> list[dict[str, Any]]:
query: dict[str, Any] = {
"offset": offset,
@@ -1573,7 +1570,7 @@ class BaseDatasetPopulator(BasePopulator):
history_id: str,
run_id: str,
include_items_on_terminal: bool = False,
- search: Optional[str] = None,
+ search: str | None = None,
timeout: timeout_type = DEFAULT_TIMEOUT,
) -> dict[str, Any]:
def is_terminal():
@@ -1628,7 +1625,7 @@ class BaseDatasetPopulator(BasePopulator):
usage_response.raise_for_status()
return usage_response.json()
- def get_usage_for(self, label: Optional[str]) -> dict[str, Any]:
+ def get_usage_for(self, label: str | None) -> dict[str, Any]:
label_as_str = label if label is not None else "__null__"
usage_response = self.galaxy_interactor.get(f"users/current/usage/{label_as_str}")
usage_response.raise_for_status()
@@ -1639,7 +1636,7 @@ class BaseDatasetPopulator(BasePopulator):
api_asserts.assert_status_code_is_ok(update_response)
return update_response.json()
- def set_user_preferred_object_store_id(self, store_id: Optional[str]) -> None:
+ def set_user_preferred_object_store_id(self, store_id: str | None) -> None:
user_properties = self.update_user({"preferred_object_store_id": store_id})
assert user_properties["preferred_object_store_id"] == store_id
@@ -1661,7 +1658,7 @@ class BaseDatasetPopulator(BasePopulator):
update_response.raise_for_status()
return update_response
- def create_role(self, user_ids: list, description: Optional[str] = None, role_type="admin") -> dict:
+ def create_role(self, user_ids: list, description: str | None = None, role_type="admin") -> dict:
using_requirement("admin")
payload = {
"name": self.get_random_name(prefix="testpop"),
@@ -1753,7 +1750,7 @@ class BaseDatasetPopulator(BasePopulator):
assert update_response.status_code == 200, update_response.content
return update_response.json()
- def validate_dataset_and_wait(self, history_id, dataset_id) -> Optional[str]:
+ def validate_dataset_and_wait(self, history_id, dataset_id) -> str | None:
self.validate_dataset(history_id, dataset_id)
def validated():
@@ -2031,7 +2028,7 @@ class BaseDatasetPopulator(BasePopulator):
return imported_history_id
- def get_random_name(self, prefix: Optional[str] = None, suffix: Optional[str] = None, len: int = 10) -> str:
+ def get_random_name(self, prefix: str | None = None, suffix: str | None = None, len: int = 10) -> str:
return random_name(prefix=prefix, suffix=suffix, len=len)
def wait_for_dataset(
@@ -2086,21 +2083,21 @@ class BaseDatasetPopulator(BasePopulator):
return selectable_object_store_ids
def new_page(
- self, slug: str = "mypage", title: str = "MY PAGE", content_format: str = "html", content: Optional[str] = None
+ self, slug: str = "mypage", title: str = "MY PAGE", content_format: str = "html", content: str | None = None
) -> dict[str, Any]:
page_response = self.new_page_raw(slug=slug, title=title, content_format=content_format, content=content)
api_asserts.assert_status_code_is(page_response, 200)
return page_response.json()
def new_page_raw(
- self, slug: str = "mypage", title: str = "MY PAGE", content_format: str = "html", content: Optional[str] = None
+ self, slug: str = "mypage", title: str = "MY PAGE", content_format: str = "html", content: str | None = None
) -> Response:
page_request = self.new_page_payload(slug=slug, title=title, content_format=content_format, content=content)
page_response = self._post("pages", page_request, json=True)
return page_response
def new_page_payload(
- self, slug: str = "mypage", title: str = "MY PAGE", content_format: str = "html", content: Optional[str] = None
+ self, slug: str = "mypage", title: str = "MY PAGE", content_format: str = "html", content: str | None = None
) -> dict[str, str]:
if content is None:
if content_format == "html":
@@ -2120,7 +2117,7 @@ class BaseDatasetPopulator(BasePopulator):
def new_history_page_raw(
self,
history_id: str,
- title: Optional[str] = None,
+ title: str | None = None,
content: str = "",
content_format: str = "markdown",
) -> Response:
@@ -2136,7 +2133,7 @@ class BaseDatasetPopulator(BasePopulator):
def new_history_page(
self,
history_id: str,
- title: Optional[str] = None,
+ title: str | None = None,
content: str = "",
content_format: str = "markdown",
) -> dict[str, Any]:
@@ -2158,8 +2155,8 @@ class BaseDatasetPopulator(BasePopulator):
self,
page_id: str,
content: str,
- title: Optional[str] = None,
- edit_source: Optional[str] = None,
+ title: str | None = None,
+ edit_source: str | None = None,
) -> Response:
payload: dict[str, Any] = {"content": content, "content_format": "markdown"}
if title:
@@ -2172,8 +2169,8 @@ class BaseDatasetPopulator(BasePopulator):
self,
page_id: str,
content: str,
- title: Optional[str] = None,
- edit_source: Optional[str] = None,
+ title: str | None = None,
+ edit_source: str | None = None,
) -> dict[str, Any]:
response = self.update_history_page_raw(page_id, content=content, title=title, edit_source=edit_source)
api_asserts.assert_status_code_is(response, 200)
@@ -2198,7 +2195,7 @@ class BaseDatasetPopulator(BasePopulator):
page_id: str,
query: str,
agent_type: str = "page_assistant",
- exchange_id: Optional[str] = None,
+ exchange_id: str | None = None,
):
payload: dict[str, Any] = {"query": query, "page_id": page_id}
if exchange_id is not None:
@@ -2210,7 +2207,7 @@ class BaseDatasetPopulator(BasePopulator):
page_id: str,
query: str,
agent_type: str = "page_assistant",
- exchange_id: Optional[str] = None,
+ exchange_id: str | None = None,
) -> dict[str, Any]:
response = self.send_page_chat_raw(page_id, query, agent_type=agent_type, exchange_id=exchange_id)
api_asserts.assert_status_code_is(response, 200)
@@ -2272,7 +2269,7 @@ class BaseDatasetPopulator(BasePopulator):
self.wait_on_task_id(export_record["task_uuid"])
def archive_history(
- self, history_id: str, export_record_id: Optional[str] = None, purge_history: Optional[bool] = False
+ self, history_id: str, export_record_id: str | None = None, purge_history: bool | None = False
) -> Response:
payload = (
{
@@ -2285,11 +2282,11 @@ class BaseDatasetPopulator(BasePopulator):
archive_response = self._post(f"histories/{history_id}/archive", data=payload, json=True)
return archive_response
- def restore_archived_history(self, history_id: str, force: Optional[bool] = None) -> Response:
+ def restore_archived_history(self, history_id: str, force: bool | None = None) -> Response:
restore_response = self._put(f"histories/{history_id}/archive/restore{f'?force={force}' if force else ''}")
return restore_response
- def get_archived_histories(self, query: Optional[str] = None) -> list[dict[str, Any]]:
+ def get_archived_histories(self, query: str | None = None) -> list[dict[str, Any]]:
if query:
query = f"?{query}"
index_response = self._get(f"histories/archived{query if query else ''}")
@@ -2336,8 +2333,8 @@ class DatasetPopulator(GalaxyInteractorHttpMixin, BaseDatasetPopulator):
def _test_history(
self,
require_new: bool = True,
- cleanup_callback: Optional[Callable[[str], None]] = None,
- name: Optional[str] = None,
+ cleanup_callback: Callable[[str], None] | None = None,
+ name: str | None = None,
) -> Generator[str, None, None]:
with self.galaxy_interactor.test_history(
require_new=require_new, cleanup_callback=cleanup_callback
@@ -2362,7 +2359,7 @@ class BaseCredentialsPopulator(BasePopulator):
source_version: str = DEFAULT_SOURCE_VERSION,
service_name: str = DEFAULT_SERVICE_NAME,
service_version: str = DEFAULT_SERVICE_VERSION,
- group_name: Optional[str] = None,
+ group_name: str | None = None,
) -> dict:
"""Build and return a credentials payload dict without posting it."""
if group_name is None:
@@ -2403,8 +2400,8 @@ class BaseCredentialsPopulator(BasePopulator):
def list_credentials(
self,
- source_type: Optional[str] = None,
- source_id: Optional[str] = None,
+ source_type: str | None = None,
+ source_id: str | None = None,
include_definition: bool = False,
expected_status: int = 200,
) -> list:
@@ -2443,7 +2440,7 @@ class BaseCredentialsPopulator(BasePopulator):
source_id: str,
source_version: str,
user_credentials_id: str,
- current_group_id: Optional[str],
+ current_group_id: str | None,
expected_status: int = 204,
) -> None:
"""PUT /api/users/current/credentials to select (or unset) the current group."""
@@ -2544,7 +2541,7 @@ class CredentialsPopulator(GalaxyInteractorHttpMixin, BaseCredentialsPopulator):
# Things gxformat2 knows how to upload as workflows
-YamlContentT = Union[StrPath, dict]
+YamlContentT = StrPath | dict
class BaseWorkflowPopulator(BasePopulator):
@@ -2569,7 +2566,7 @@ class BaseWorkflowPopulator(BasePopulator):
def load_random_x2_workflow(self, name: str) -> dict:
return self.load_workflow(name, content=workflow_random_x2_str)
- def load_workflow_from_resource(self, name: str, filename: Optional[str] = None) -> dict:
+ def load_workflow_from_resource(self, name: str, filename: str | None = None) -> dict:
if filename is None:
filename = f"data/{name}.ga"
content = resource_string(__name__, filename)
@@ -2579,7 +2576,7 @@ class BaseWorkflowPopulator(BasePopulator):
workflow = self.load_workflow(name)
return self.create_workflow(workflow, **create_kwds)
- def import_workflow_from_path_raw(self, from_path: str, object_id: Optional[str] = None) -> Response:
+ def import_workflow_from_path_raw(self, from_path: str, object_id: str | None = None) -> Response:
data = dict(
from_path=from_path,
object_id=object_id,
@@ -2587,7 +2584,7 @@ class BaseWorkflowPopulator(BasePopulator):
import_response = self._post("workflows", data=data)
return import_response
- def import_workflow_from_path(self, from_path: str, object_id: Optional[str] = None) -> str:
+ def import_workflow_from_path(self, from_path: str, object_id: str | None = None) -> str:
import_response = self.import_workflow_from_path_raw(from_path, object_id)
api_asserts.assert_status_code_is(import_response, 200)
return import_response.json()["id"]
@@ -2621,8 +2618,7 @@ class BaseWorkflowPopulator(BasePopulator):
else:
workflow = {"yaml_content": yaml_content} if not isinstance(yaml_content, dict) else yaml_content
- name = kwds.get("name")
- if name is not None:
+ if (name := kwds.get("name")) is not None:
workflow["name"] = name
import_kwds = {"fill_defaults": kwds.get("fill_defaults", True)}
if kwds.get("publish"):
@@ -2645,7 +2641,7 @@ class BaseWorkflowPopulator(BasePopulator):
def wait_for_invocation(
self,
- workflow_id: Optional[str],
+ workflow_id: str | None,
invocation_id: str,
timeout: timeout_type = DEFAULT_TIMEOUT,
assert_ok: bool = True,
@@ -2679,7 +2675,7 @@ class BaseWorkflowPopulator(BasePopulator):
history_id: str,
assert_ok: bool = True,
timeout: timeout_type = DEFAULT_TIMEOUT,
- expected_invocation_count: Optional[int] = None,
+ expected_invocation_count: int | None = None,
) -> None:
if expected_invocation_count is not None:
@@ -2698,7 +2694,7 @@ class BaseWorkflowPopulator(BasePopulator):
def wait_for_workflow(
self,
- workflow_id: Optional[str],
+ workflow_id: str | None,
invocation_id: str,
history_id: str,
assert_ok: bool = True,
@@ -2736,9 +2732,9 @@ class BaseWorkflowPopulator(BasePopulator):
def create_invocation_from_store_raw(
self,
history_id: str,
- store_dict: Optional[dict[str, Any]] = None,
- store_path: Optional[str] = None,
- model_store_format: Optional[str] = None,
+ store_dict: dict[str, Any] | None = None,
+ store_path: str | None = None,
+ model_store_format: str | None = None,
) -> Response:
url = "invocations/from_store"
payload = _store_payload(store_dict=store_dict, store_path=store_path, model_store_format=model_store_format)
@@ -2749,9 +2745,9 @@ class BaseWorkflowPopulator(BasePopulator):
def create_invocation_from_store(
self,
history_id: str,
- store_dict: Optional[dict[str, Any]] = None,
- store_path: Optional[str] = None,
- model_store_format: Optional[str] = None,
+ store_dict: dict[str, Any] | None = None,
+ store_path: str | None = None,
+ model_store_format: str | None = None,
) -> list[dict[str, Any]]:
create_response = self.create_invocation_from_store_raw(
history_id, store_dict=store_dict, store_path=store_path, model_store_format=model_store_format
@@ -2780,9 +2776,9 @@ class BaseWorkflowPopulator(BasePopulator):
def invoke_workflow(
self,
workflow_id: str,
- history_id: Optional[str] = None,
- inputs: Optional[dict] = None,
- request: Optional[dict] = None,
+ history_id: str | None = None,
+ inputs: dict | None = None,
+ request: dict | None = None,
inputs_by: str = "step_index",
) -> Response:
if inputs is None:
@@ -2804,9 +2800,9 @@ class BaseWorkflowPopulator(BasePopulator):
def invoke_workflow_and_assert_ok(
self,
workflow_id: str,
- history_id: Optional[str] = None,
- inputs: Optional[dict] = None,
- request: Optional[dict] = None,
+ history_id: str | None = None,
+ inputs: dict | None = None,
+ request: dict | None = None,
inputs_by: str = "step_index",
) -> str:
invocation_response = self.invoke_workflow(
@@ -2819,9 +2815,9 @@ class BaseWorkflowPopulator(BasePopulator):
def invoke_workflow_and_wait(
self,
workflow_id: str,
- history_id: Optional[str] = None,
- inputs: Optional[dict] = None,
- request: Optional[dict] = None,
+ history_id: str | None = None,
+ inputs: dict | None = None,
+ request: dict | None = None,
assert_ok: bool = True,
) -> Response:
invoke_return = self.invoke_workflow(workflow_id, history_id=history_id, inputs=inputs, request=request)
@@ -2852,11 +2848,11 @@ class BaseWorkflowPopulator(BasePopulator):
def download_workflow(
self,
workflow_id: str,
- style: Optional[str] = None,
- history_id: Optional[str] = None,
- instance: Optional[bool] = None,
- version: Optional[int] = None,
- preserve_external_subworkflow_links: Optional[bool] = None,
+ style: str | None = None,
+ history_id: str | None = None,
+ instance: bool | None = None,
+ version: int | None = None,
+ preserve_external_subworkflow_links: bool | None = None,
) -> dict:
params: dict[str, Any] = {}
if style is not None:
@@ -2896,9 +2892,9 @@ class BaseWorkflowPopulator(BasePopulator):
self,
workflow_id: str,
actions: list,
- dry_run: Optional[bool] = None,
- style: Optional[str] = None,
- version: Optional[int] = None,
+ dry_run: bool | None = None,
+ style: str | None = None,
+ version: int | None = None,
) -> Response:
data: dict[str, Any] = dict(
actions=actions,
@@ -2923,21 +2919,21 @@ class BaseWorkflowPopulator(BasePopulator):
def run_workflow(
self,
has_workflow: YamlContentT,
- test_data: Optional[Union[str, dict]] = None,
- history_id: Optional[str] = None,
+ test_data: str | dict | None = None,
+ history_id: str | None = None,
wait: bool = True,
- source_type: Optional[str] = None,
+ source_type: str | None = None,
jobs_descriptions=None,
expected_response: int = 200,
assert_ok: bool = True,
- client_convert: Optional[bool] = None,
- extra_invocation_kwds: Optional[dict[str, Any]] = None,
+ client_convert: bool | None = None,
+ extra_invocation_kwds: dict[str, Any] | None = None,
round_trip_format_conversion: bool = False,
invocations: int = 1,
use_cached_job: bool = False,
copy_inputs_to_history: bool = False,
- job_dir: Optional[str] = None,
- test_data_format: Optional[Literal["cwl_style"]] = None,
+ job_dir: str | None = None,
+ test_data_format: Literal["cwl_style"] | None = None,
):
"""High-level wrapper around workflow API, etc. to invoke format 2 workflows.
@@ -3152,10 +3148,10 @@ class BaseWorkflowPopulator(BasePopulator):
def setup_workflow_run(
self,
- workflow: Optional[dict[str, Any]] = None,
+ workflow: dict[str, Any] | None = None,
inputs_by: str = "step_id",
- history_id: Optional[str] = None,
- workflow_id: Optional[str] = None,
+ history_id: str | None = None,
+ workflow_id: str | None = None,
) -> tuple[dict[str, Any], str, str]:
ds_entry = self.dataset_populator.ds_entry
if not workflow_id:
@@ -3163,9 +3159,9 @@ class BaseWorkflowPopulator(BasePopulator):
workflow_id = self.create_workflow(workflow)
if not history_id:
history_id = self.dataset_populator.new_history()
- hda1: Optional[dict[str, Any]] = None
- hda2: Optional[dict[str, Any]] = None
- label_map: Optional[dict[str, Any]] = None
+ hda1: dict[str, Any] | None = None
+ hda2: dict[str, Any] | None = None
+ label_map: dict[str, Any] | None = None
if inputs_by != "url":
hda1 = self.dataset_populator.new_dataset(history_id, content="1 2 3", wait=True)
hda2 = self.dataset_populator.new_dataset(history_id, content="4 5 6", wait=True)
@@ -3219,7 +3215,7 @@ class BaseWorkflowPopulator(BasePopulator):
return jobs
def wait_for_invocation_and_jobs(
- self, history_id: str, workflow_id: Optional[str], invocation_id: str, assert_ok: bool = True
+ self, history_id: str, workflow_id: str | None, invocation_id: str, assert_ok: bool = True
) -> None:
"""Wait for invocation to be scheduled and all jobs to complete.
@@ -3234,7 +3230,7 @@ class BaseWorkflowPopulator(BasePopulator):
self.dataset_populator.wait_for_history_jobs(history_id, assert_ok=assert_ok)
time.sleep(0.5)
- def get_invocation_completion(self, invocation_id: str) -> Optional[dict[str, Any]]:
+ def get_invocation_completion(self, invocation_id: str) -> dict[str, Any] | None:
"""Get completion record for an invocation.
Returns the completion record if it exists, or None if the invocation
@@ -3273,14 +3269,14 @@ class BaseWorkflowPopulator(BasePopulator):
def index(
self,
- show_shared: Optional[bool] = None,
- show_published: Optional[bool] = None,
- sort_by: Optional[str] = None,
- sort_desc: Optional[bool] = None,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- search: Optional[str] = None,
- skip_step_counts: Optional[bool] = None,
+ show_shared: bool | None = None,
+ show_published: bool | None = None,
+ sort_by: str | None = None,
+ sort_desc: bool | None = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ search: str | None = None,
+ skip_step_counts: bool | None = None,
):
endpoint = "workflows?"
if show_shared is not None:
@@ -3305,13 +3301,13 @@ class BaseWorkflowPopulator(BasePopulator):
def index_ids(
self,
- show_shared: Optional[bool] = None,
- show_published: Optional[bool] = None,
- sort_by: Optional[str] = None,
- sort_desc: Optional[bool] = None,
- limit: Optional[int] = None,
- offset: Optional[int] = None,
- search: Optional[str] = None,
+ show_shared: bool | None = None,
+ show_published: bool | None = None,
+ sort_by: str | None = None,
+ sort_desc: bool | None = None,
+ limit: int | None = None,
+ offset: int | None = None,
+ search: str | None = None,
):
workflows = self.index(
show_shared=show_shared,
@@ -3359,7 +3355,7 @@ class WorkflowPopulator(GalaxyInteractorHttpMixin, BaseWorkflowPopulator):
assert upload_response.status_code == 200, upload_response.text
return upload_response.json()
- def build_module(self, step_type: str, content_id: Optional[str] = None, inputs: Optional[dict[str, Any]] = None):
+ def build_module(self, step_type: str, content_id: str | None = None, inputs: dict[str, Any] | None = None):
payload = {"inputs": inputs or {}, "type": step_type, "content_id": content_id}
response = self._post("workflows/build_module", data=payload, json=True)
assert response.status_code == 200, response
@@ -3452,7 +3448,7 @@ class WorkflowPopulator(GalaxyInteractorHttpMixin, BaseWorkflowPopulator):
return workflow_dict
@staticmethod
- def _link(link: str, output_name: Optional[str] = None) -> dict[str, Any]:
+ def _link(link: str, output_name: str | None = None) -> dict[str, Any]:
if output_name is not None:
link = f"{str(link)}/{output_name}"
return {"$link": link}
@@ -3483,7 +3479,7 @@ class CwlPopulator:
history_id: str,
assert_ok: bool = True,
) -> CwlToolRun:
- galaxy_tool_id: Optional[str] = tool_id
+ galaxy_tool_id: str | None = tool_id
tool_uuid = None
if os.path.exists(tool_id):
@@ -3526,10 +3522,10 @@ class CwlPopulator:
def run_cwl_job(
self,
artifact: str,
- job_path: Optional[str] = None,
- job: Optional[dict] = None,
- test_data_directory: Optional[str] = None,
- history_id: Optional[str] = None,
+ job_path: str | None = None,
+ job: dict | None = None,
+ test_data_directory: str | None = None,
+ history_id: str | None = None,
assert_ok: bool = True,
) -> CwlRun:
"""
@@ -3640,7 +3636,7 @@ class LibraryPopulator:
return create_response
def create_from_store(
- self, store_dict: Optional[dict[str, Any]] = None, store_path: Optional[str] = None
+ self, store_dict: dict[str, Any] | None = None, store_path: str | None = None
) -> list[dict[str, Any]]:
payload = _store_payload(store_dict=store_dict, store_path=store_path)
create_response = self.create_from_store_raw(payload)
@@ -3679,12 +3675,12 @@ class LibraryPopulator:
def get_permissions(
self,
library_id,
- scope: Optional[str] = "current",
- is_library_access: Optional[bool] = False,
- page: Optional[int] = 1,
- page_limit: Optional[int] = 1000,
- q: Optional[str] = None,
- admin: Optional[bool] = True,
+ scope: str | None = "current",
+ is_library_access: bool | None = False,
+ page: int | None = 1,
+ page_limit: int | None = 1000,
+ q: str | None = None,
+ admin: bool | None = True,
):
query = f"&q={q}" if q else ""
response = self.galaxy_interactor.get(
@@ -4144,7 +4140,7 @@ class BaseDatasetCollectionPopulator:
payload["__files"] = kwds.pop("__files")
return payload
- def wait_for_fetched_collection(self, fetch_response: Union[dict[str, Any], Response]):
+ def wait_for_fetched_collection(self, fetch_response: dict[str, Any] | Response):
fetch_response_dict: dict[str, Any]
if isinstance(fetch_response, Response):
fetch_response_dict = fetch_response.json()
@@ -4433,7 +4429,7 @@ def stage_inputs(
use_fetch_api: bool = True,
to_posix_lines: bool = True,
tool_or_workflow: Literal["tool", "workflow"] = "workflow",
- job_dir: Optional[str] = None,
+ job_dir: str | None = None,
) -> tuple[dict[str, Any], list[dict[str, Any]]]:
"""Alternative to load_data_dict that uses production-style workflow inputs."""
test_data_resolver = TestDataResolver()
@@ -4518,9 +4514,9 @@ def wait_on_state(
def _store_payload(
- store_dict: Optional[dict[str, Any]] = None,
- store_path: Optional[str] = None,
- model_store_format: Optional[str] = None,
+ store_dict: dict[str, Any] | None = None,
+ store_path: str | None = None,
+ model_store_format: str | None = None,
) -> dict[str, Any]:
payload: dict[str, Any] = {}
# Ensure only one store method set.
@@ -4538,7 +4534,6 @@ def _store_payload(
class DescribeToolExecutionOutput:
-
def __init__(self, dataset_populator: BaseDatasetPopulator, history_id: str, hda_id: str):
self._dataset_populator = dataset_populator
self._history_id = history_id
@@ -4596,7 +4591,6 @@ class DescribeToolExecutionOutput:
class DescribeToolExecutionOutputCollection:
-
def __init__(self, dataset_populator: BaseDatasetPopulator, history_id: str, hdca_id: str):
self._dataset_populator = dataset_populator
self._history_id = history_id
@@ -4619,7 +4613,7 @@ class DescribeToolExecutionOutputCollection:
raise AssertionError("Collection contained {count} elements and not the expected {n} elements")
return self
- def with_element_dict(self, index: Union[str, int]) -> dict[str, Any]:
+ def with_element_dict(self, index: str | int) -> dict[str, Any]:
elements = self.elements
if isinstance(index, int):
element_dict = elements[index]
@@ -4627,7 +4621,7 @@ class DescribeToolExecutionOutputCollection:
element_dict = [e for e in elements if e["element_identifier"] == index][0]
return element_dict
- def with_dataset_element(self, index: Union[str, int]) -> "DescribeToolExecutionOutput":
+ def with_dataset_element(self, index: str | int) -> "DescribeToolExecutionOutput":
element_dict = self.with_element_dict(index)
element_object = element_dict["object"]
return DescribeToolExecutionOutput(self._dataset_populator, self._history_id, element_object["id"])
@@ -4638,7 +4632,7 @@ class DescribeToolExecutionOutputCollection:
return self
# aliases that might help make tests more like English in particular cases.
- def assert_has_dataset_element(self, index: Union[str, int]) -> "DescribeToolExecutionOutput":
+ def assert_has_dataset_element(self, index: str | int) -> "DescribeToolExecutionOutput":
return self.with_dataset_element(index)
def assert_collection_type_is(self, collection_type: str):
@@ -4646,12 +4640,11 @@ class DescribeToolExecutionOutputCollection:
class DescribeJob:
-
def __init__(self, dataset_populator: BaseDatasetPopulator, history_id: str, job_id: str):
self._dataset_populator = dataset_populator
self._history_id = history_id
self._job_id = job_id
- self._final_details: Optional[dict[str, Any]] = None
+ self._final_details: dict[str, Any] | None = None
def _wait_for(self):
if self._final_details is None:
@@ -4682,11 +4675,11 @@ class DescribeJob:
def with_single_output(self) -> DescribeToolExecutionOutput:
return self.with_output(0)
- def with_output(self, output: Union[str, int]) -> DescribeToolExecutionOutput:
+ def with_output(self, output: str | int) -> DescribeToolExecutionOutput:
self.with_final_state("ok")
outputs = self._dataset_populator.job_outputs(self._job_id)
by_name = isinstance(output, str)
- dataset_id: Optional[str] = None
+ dataset_id: str | None = None
if by_name:
for output_assoc in outputs:
if output_assoc["name"] == output:
@@ -4699,7 +4692,7 @@ class DescribeJob:
return DescribeToolExecutionOutput(self._dataset_populator, self._history_id, dataset_id)
# aliases that might help make tests more like English in particular cases.
- def assert_has_output(self, output: Union[str, int]) -> DescribeToolExecutionOutput:
+ def assert_has_output(self, output: str | int) -> DescribeToolExecutionOutput:
return self.with_output(output)
@property
@@ -4708,7 +4701,7 @@ class DescribeJob:
class DescribeFailure:
- def __init__(self, response: Response, tool_request: Optional[dict[str, Any]] = None):
+ def __init__(self, response: Response, tool_request: dict[str, Any] | None = None):
self._response = response
self._tool_request = tool_request
@@ -4736,8 +4729,7 @@ class DescribeFailure:
class RequiredTool:
-
- def __init__(self, dataset_populator: BaseDatasetPopulator, tool_id: str, default_history_id: Optional[str]):
+ def __init__(self, dataset_populator: BaseDatasetPopulator, tool_id: str, default_history_id: str | None):
self._dataset_populator = dataset_populator
self._tool_id = tool_id
self._default_history_id = default_history_id
@@ -4751,7 +4743,7 @@ class RequiredTool:
class DescribeToolInputs:
_input_format: INPUT_FORMAT_T = "legacy"
- _inputs: Optional[dict[str, Any]]
+ _inputs: dict[str, Any] | None
def __init__(self, input_format: INPUT_FORMAT_T):
self._input_format = input_format
@@ -4787,11 +4779,11 @@ class DescribeToolInputs:
class DescribeToolExecution:
- _history_id: Optional[str] = None
- _execute_response: Optional[Response] = None
- _input_format: Optional[INPUT_FORMAT_T] = None
+ _history_id: str | None = None
+ _execute_response: Response | None = None
+ _input_format: INPUT_FORMAT_T | None = None
_inputs: dict[str, Any]
- _tool_request_id: Optional[str] = None # if input_format == "request" request ID
+ _tool_request_id: str | None = None # if input_format == "request" request ID
def __init__(self, dataset_populator: BaseDatasetPopulator, tool_id: str, use_cached_job: bool = False) -> None:
self._dataset_populator = dataset_populator
@@ -4806,7 +4798,7 @@ class DescribeToolExecution:
self._history_id = has_history_id._history_id
return self
- def with_inputs(self, inputs: Union[DescribeToolInputs, dict[str, Any]]) -> Self:
+ def with_inputs(self, inputs: DescribeToolInputs | dict[str, Any]) -> Self:
if isinstance(inputs, DescribeToolInputs):
self._inputs = inputs._inputs or {}
self._input_format = inputs._input_format
@@ -4911,7 +4903,7 @@ class DescribeToolExecution:
raise AssertionError(f"Expected tool execution to produce {n} implicit but it produced {len(collections)}")
return self
- def assert_creates_implicit_collection(self, index: Union[str, int]) -> "DescribeToolExecutionOutputCollection":
+ def assert_creates_implicit_collection(self, index: str | int) -> "DescribeToolExecutionOutputCollection":
collections = self._implicit_collections
assert isinstance(index, int) # TODO: implement and then prefer str.
history_id = self._ensure_history_id
@@ -5031,11 +5023,10 @@ class GiWorkflowPopulator(GiHttpMixin, BaseWorkflowPopulator):
self.dataset_populator = GiDatasetPopulator(gi)
-ListContentsDescription = Union[list[str], list[tuple[str, str]]]
+ListContentsDescription = list[str] | list[tuple[str, str]]
class TargetHistory:
-
def __init__(
self,
dataset_populator: DatasetPopulator,
@@ -5053,7 +5044,7 @@ class TargetHistory:
def with_dataset(
self,
content: str,
- named: Optional[str] = None,
+ named: str | None = None,
) -> "HasSrcDict":
kwd = {}
if named is not None:
@@ -5071,7 +5062,7 @@ class TargetHistory:
self,
filename: str,
file_type: str,
- named: Optional[str] = None,
+ named: str | None = None,
) -> "HasSrcDict":
"""Upload a real test-data file with an explicit ``file_type`` (ext preserved).
@@ -5096,8 +5087,8 @@ class TargetHistory:
def with_deferred_dataset(
self,
uri: str,
- named: Optional[str] = None,
- ext: Optional[str] = None,
+ named: str | None = None,
+ ext: str | None = None,
) -> "HasSrcDict":
kwd = {}
if named is not None:
@@ -5112,8 +5103,8 @@ class TargetHistory:
def with_deferred_dataset_for_test_file(
self,
filename: str,
- named: Optional[str] = None,
- ext: Optional[str] = None,
+ named: str | None = None,
+ ext: str | None = None,
) -> "HasSrcDict":
base64_url = self._dataset_populator.base64_url_for_test_file(filename)
return self.with_deferred_dataset(base64_url, named=named, ext=ext)
@@ -5135,21 +5126,21 @@ class TargetHistory:
)
)
- def with_pair(self, contents: Optional[list[str]] = None) -> "HasSrcDict":
+ def with_pair(self, contents: list[str] | None = None) -> "HasSrcDict":
return self._fetch_response(
self._dataset_collection_populator.create_pair_in_history(
self._history_id, contents=contents, direct_upload=True, wait=True
)
)
- def with_list(self, contents: Optional[ListContentsDescription] = None) -> "HasSrcDict":
+ def with_list(self, contents: ListContentsDescription | None = None) -> "HasSrcDict":
return self._fetch_response(
self._dataset_collection_populator.create_list_in_history(
self._history_id, contents=contents, direct_upload=True, wait=True
)
)
- def with_sample_sheet(self, contents: Optional[ListContentsDescription] = None) -> "HasSrcDict":
+ def with_sample_sheet(self, contents: ListContentsDescription | None = None) -> "HasSrcDict":
if contents is None:
contents = [("foo", "text for foo element")]
create_response = self._dataset_collection_populator.create_sample_sheet(
@@ -5183,9 +5174,9 @@ class SrcDict(TypedDict):
class HasSrcDict:
- api_object: Union[str, dict[str, Any]]
+ api_object: str | dict[str, Any]
- def __init__(self, src_type: str, api_object: Union[str, dict[str, Any]]):
+ def __init__(self, src_type: str, api_object: str | dict[str, Any]):
self.src_type = src_type
self.api_object = api_object
diff --git a/lib/galaxy_test/base/sse.py b/lib/galaxy_test/base/sse.py
index d98ab7c6c52..ba936f9c89e 100644
--- a/lib/galaxy_test/base/sse.py
+++ b/lib/galaxy_test/base/sse.py
@@ -10,7 +10,6 @@ thread instead of silently swallowing them.
import queue
import threading
from collections.abc import Callable
-from typing import Optional
import requests
@@ -60,7 +59,7 @@ class SSELineListener:
self,
url: str,
api_key: str,
- headers: Optional[dict] = None,
+ headers: dict | None = None,
timeout: int = 30,
) -> None:
self.url = url
@@ -116,7 +115,7 @@ class SSELineListener:
return wait_on(_check, f"SSE {event_type} matching predicate", timeout=timeout)
- def get_events(self, event_type: Optional[str] = None) -> list[dict]:
+ def get_events(self, event_type: str | None = None) -> list[dict]:
"""Return all collected events so far, optionally filtered by type."""
all_events = parse_sse_events("".join(self._collected))
if event_type is None:
diff --git a/lib/galaxy_test/base/testcase.py b/lib/galaxy_test/base/testcase.py
index 58acf00ea40..8c3fe9374a8 100644
--- a/lib/galaxy_test/base/testcase.py
+++ b/lib/galaxy_test/base/testcase.py
@@ -1,7 +1,6 @@
import logging
from typing import (
Any,
- Optional,
)
import pytest
@@ -17,7 +16,7 @@ from galaxy_test.base.env import (
log = logging.getLogger(__name__)
-def host_port_and_url(test_driver: Optional[Any]) -> GalaxyTarget:
+def host_port_and_url(test_driver: Any | None) -> GalaxyTarget:
host, port, url = target_url_parts()
server_wrapper = test_driver and test_driver.server_wrappers and test_driver.server_wrappers[0]
if server_wrapper:
@@ -36,13 +35,13 @@ class FunctionalTestCase(TestCase):
server is already running.
"""
- galaxy_driver_class: Optional[type] = None
+ galaxy_driver_class: type | None = None
host: str
- port: Optional[str]
+ port: str | None
url: str
keepOutdir: str
test_data_resolver: TestDataResolver
- _test_driver: Optional[Any]
+ _test_driver: Any | None
def setUp(self) -> None:
self.host, self.port, self.url = host_port_and_url(self._test_driver)
diff --git a/lib/galaxy_test/base/uses_shed_api.py b/lib/galaxy_test/base/uses_shed_api.py
index e53ac075b4d..cca65f080e8 100644
--- a/lib/galaxy_test/base/uses_shed_api.py
+++ b/lib/galaxy_test/base/uses_shed_api.py
@@ -2,7 +2,6 @@ import abc
from collections.abc import Callable
from typing import (
Any,
- Optional,
)
from unittest import SkipTest
@@ -37,7 +36,7 @@ class UsesShedApi:
name: str,
changeset: str,
tool_shed_url: str = DEFAULT_TOOL_SHED_URL,
- tool_panel_section_id: Optional[str] = None,
+ tool_panel_section_id: str | None = None,
) -> dict[str, Any]:
payload = {"tool_shed_url": tool_shed_url, "name": name, "owner": owner, "changeset_revision": changeset}
if tool_panel_section_id:
@@ -52,7 +51,7 @@ class UsesShedApi:
name: str,
changeset: str,
tool_shed_url: str = DEFAULT_TOOL_SHED_URL,
- tool_panel_section_id: Optional[str] = None,
+ tool_panel_section_id: str | None = None,
) -> dict[str, Any]:
try:
return self.repository_operation(
@@ -76,7 +75,7 @@ class UsesShedApi:
)
def index_repositories(
- self, owner: Optional[str] = None, name: Optional[str] = None, changeset: Optional[str] = None
+ self, owner: str | None = None, name: str | None = None, changeset: str | None = None
) -> list[dict[str, Any]]:
params: dict[str, str] = {}
if owner is not None:
@@ -92,8 +91,8 @@ class UsesShedApi:
return response.json()
def get_installed_repository_for(
- self, owner: Optional[str] = None, name: Optional[str] = None, changeset: Optional[str] = None
- ) -> Optional[dict[str, Any]]:
+ self, owner: str | None = None, name: str | None = None, changeset: str | None = None
+ ) -> dict[str, Any] | None:
index = self.index_repositories(owner, name, changeset)
if len(index) == 0:
return None
diff --git a/lib/galaxy_test/base/workflow_assertions.py b/lib/galaxy_test/base/workflow_assertions.py
index d372e92ab0f..a10edf6bafc 100644
--- a/lib/galaxy_test/base/workflow_assertions.py
+++ b/lib/galaxy_test/base/workflow_assertions.py
@@ -6,7 +6,6 @@ Mixin providing workflow structure assertions shared between API and Selenium te
import operator
from json import loads
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -18,7 +17,7 @@ class WorkflowStructureAssertions:
"""Mixin providing workflow structure verification methods."""
def assert_steps_of_type(
- self, workflow: "dict[str, Any]", step_type: str, expected_len: Optional[int] = None
+ self, workflow: "dict[str, Any]", step_type: str, expected_len: int | None = None
) -> "list[dict[str, Any]]":
"""Get steps of given type from workflow, optionally asserting count."""
steps = [s for s in workflow["steps"].values() if s["type"] == step_type]
@@ -89,11 +88,11 @@ class WorkflowStructureAssertions:
def check_workflow(
self,
workflow: "dict[str, Any]",
- step_count: Optional[int] = None,
+ step_count: int | None = None,
verify_connected: bool = False,
- data_input_count: Optional[int] = None,
- data_collection_input_count: Optional[int] = None,
- tool_ids: "Optional[list[str]]" = None,
+ data_input_count: int | None = None,
+ data_collection_input_count: int | None = None,
+ tool_ids: "list[str] | None" = None,
) -> None:
"""Check workflow against expected structure."""
steps = workflow["steps"]
diff --git a/lib/galaxy_test/driver/driver_util.py b/lib/galaxy_test/driver/driver_util.py
index 7b4147c7ea7..dcfd2e6e38c 100644
--- a/lib/galaxy_test/driver/driver_util.py
+++ b/lib/galaxy_test/driver/driver_util.py
@@ -17,7 +17,6 @@ import time
from pathlib import Path
from typing import (
Any,
- Optional,
)
from urllib.parse import urlparse
@@ -151,7 +150,7 @@ def setup_galaxy_config(
new_file_path = tempfile.mkdtemp(prefix="new_files_path_", dir=tmpdir)
job_working_directory = tempfile.mkdtemp(prefix="job_working_directory_", dir=tmpdir)
- user_library_import_dir: Optional[str]
+ user_library_import_dir: str | None
if use_test_file_dir:
first_test_file_dir = ensure_test_file_dir_set()
if not os.path.isabs(first_test_file_dir):
@@ -416,7 +415,7 @@ def database_conf(db_path, prefix="GALAXY", prefer_template_database=False):
def install_database_conf(db_path, default_merged=False):
- install_galaxy_database_connection: Optional[str]
+ install_galaxy_database_connection: str | None
if "GALAXY_TEST_INSTALL_DBURI" in os.environ:
install_galaxy_database_connection = os.environ["GALAXY_TEST_INSTALL_DBURI"]
elif asbool(os.environ.get("GALAXY_TEST_INSTALL_DB_MERGED", default_merged)):
@@ -502,7 +501,7 @@ def wait_for_http_server(host, port, prefix=None, sleep_amount=0.1, sleep_tries=
raise Exception(message)
-def attempt_port(port: int) -> Optional[int]:
+def attempt_port(port: int) -> int | None:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind(("", port))
@@ -643,7 +642,7 @@ class ServerWrapper:
self.port = port
self.prefix = prefix
- def get_logs(self) -> Optional[str]:
+ def get_logs(self) -> str | None:
# Subclasses can implement a way to return relevant logs
pass
@@ -771,7 +770,7 @@ def _test_fast_app_slot() -> dict:
return {}
-def _find_root_wsgi_mount(app: FastAPI) -> Optional[Mount]:
+def _find_root_wsgi_mount(app: FastAPI) -> Mount | None:
"""Locate the ``Mount("/", wsgi_handler)`` that ``initialize_fast_app``
installs as the final route on the FastAPI app.
"""
@@ -1023,8 +1022,8 @@ class GalaxyTestDriver(TestDriver):
self.testing_shed_tools = getattr(config_object, "testing_shed_tools", False)
- default_tool_conf: Optional[str]
- datatypes_conf_override: Optional[str]
+ default_tool_conf: str | None
+ datatypes_conf_override: str | None
framework_tools_and_types = getattr(config_object, "framework_tool_and_types", False)
if framework_tools_and_types:
default_tool_conf = FRAMEWORK_SAMPLE_TOOLS_CONF
@@ -1048,7 +1047,7 @@ class GalaxyTestDriver(TestDriver):
self._configure(config_object)
self._register_and_run_servers(config_object)
- def get_logs(self) -> Optional[str]:
+ def get_logs(self) -> str | None:
if not self.server_wrappers:
return None
server_wrapper = self.server_wrappers[0]
@@ -1060,7 +1059,7 @@ class GalaxyTestDriver(TestDriver):
def _register_and_run_servers(self, config_object=None, handle_config=None) -> None:
config_object = self._ensure_config_object(config_object)
- self.app: Optional[GalaxyUniverseApplication] = None
+ self.app: GalaxyUniverseApplication | None = None
if self.external_galaxy is None:
if self._saved_galaxy_config is not None:
@@ -1129,7 +1128,7 @@ class GalaxyTestDriver(TestDriver):
return config_object
def run_tool_test(
- self, tool_id: str, index: int = 0, resource_parameters: Optional[dict[str, Any]] = None, **kwd
+ self, tool_id: str, index: int = 0, resource_parameters: dict[str, Any] | None = None, **kwd
) -> None:
if resource_parameters is None:
resource_parameters = {}
diff --git a/lib/galaxy_test/driver/integration_util.py b/lib/galaxy_test/driver/integration_util.py
index c15d3580ae8..5d62f3efa69 100644
--- a/lib/galaxy_test/driver/integration_util.py
+++ b/lib/galaxy_test/driver/integration_util.py
@@ -53,7 +53,7 @@ SCRIPT_DIRECTORY = os.path.abspath(os.path.dirname(__file__))
VAULT_CONF = os.path.join(SCRIPT_DIRECTORY, "vault_conf.yml")
-def docker_run(image, name, *args, detach=True, remove=True, ports=None, env_vars: Optional[dict[str, str]] = None):
+def docker_run(image, name, *args, detach=True, remove=True, ports=None, env_vars: dict[str, str] | None = None):
cmd = ["docker", "run"]
if ports:
@@ -310,7 +310,7 @@ class ConfiguresObjectStores:
cls,
template: string.Template,
config: dict[str, Any],
- template_params: Optional[dict[str, Any]] = None,
+ template_params: dict[str, Any] | None = None,
format: ObjectStoreConfigFormat = "xml",
):
temp_directory = cls._test_driver.mkdtemp()
diff --git a/lib/galaxy_test/selenium/framework.py b/lib/galaxy_test/selenium/framework.py
index 47c12857847..7b3c0265d28 100644
--- a/lib/galaxy_test/selenium/framework.py
+++ b/lib/galaxy_test/selenium/framework.py
@@ -14,7 +14,6 @@ from functools import (
from typing import (
Any,
cast,
- Optional,
TYPE_CHECKING,
)
@@ -975,8 +974,7 @@ class RunsToolTests(NavigatesGalaxyMixin):
def _parse_repeat_key(key: str):
import re
- match = re.match(r"^(.+?)_(\d+)\|(.+)$", key)
- if match:
+ if match := re.match(r"^(.+?)_(\d+)\|(.+)$", key):
return match.group(1), int(match.group(2)), match.group(3)
return None
@@ -1221,15 +1219,13 @@ class RunsToolTests(NavigatesGalaxyMixin):
wait=False,
)
- expected_type = oc_def.get("attributes", {}).get("type")
- if expected_type:
+ if expected_type := oc_def.get("attributes", {}).get("type"):
actual_type = data_collection["collection_type"]
assert (
actual_type == expected_type
), f"Collection '{oc_def['name']}': expected type '{expected_type}', got '{actual_type}'"
- expected_count = oc_def.get("attributes", {}).get("count")
- if expected_count is not None:
+ if (expected_count := oc_def.get("attributes", {}).get("count")) is not None:
actual_count = len(data_collection["elements"])
assert actual_count == int(
expected_count
@@ -1340,7 +1336,7 @@ class RunsWorkflows(GalaxyTestSeleniumContext):
workflow_populator.upload_yaml_workflow(content, name=name, **kwds)
return name
- def workflow_run_setup_inputs(self, content: Optional[str]) -> tuple[str, dict[str, Any]]:
+ def workflow_run_setup_inputs(self, content: str | None) -> tuple[str, dict[str, Any]]:
history_id = self.current_history_id()
if content:
yaml_content = yaml.safe_load(content)
@@ -1379,9 +1375,9 @@ class RunsWorkflows(GalaxyTestSeleniumContext):
def workflow_run_and_submit(
self,
workflow_content: str,
- test_data_content: Optional[str] = None,
+ test_data_content: str | None = None,
landing_screenshot_name=None,
- inputs_specified_screenshot_name: Optional[str] = None,
+ inputs_specified_screenshot_name: str | None = None,
ensure_expanded: bool = False,
):
history_id, inputs = self.workflow_run_setup_inputs(test_data_content)
diff --git a/lib/galaxy_test/selenium/jupyter/notebook_example_library.ipynb b/lib/galaxy_test/selenium/jupyter/notebook_example_library.ipynb
index ee392d06afe..a7bed71f936 100644
--- a/lib/galaxy_test/selenium/jupyter/notebook_example_library.ipynb
+++ b/lib/galaxy_test/selenium/jupyter/notebook_example_library.ipynb
@@ -22,6 +22,7 @@
"outputs": [],
"source": [
"from galaxy.selenium.jupyter_context import init\n",
+ "\n",
"gx_selenium_context = init(config)"
]
},
diff --git a/lib/galaxy_test/selenium/jupyter/notebook_example_testing.ipynb b/lib/galaxy_test/selenium/jupyter/notebook_example_testing.ipynb
index 065248a456e..9fdcd377c81 100644
--- a/lib/galaxy_test/selenium/jupyter/notebook_example_testing.ipynb
+++ b/lib/galaxy_test/selenium/jupyter/notebook_example_testing.ipynb
@@ -22,6 +22,7 @@
"outputs": [],
"source": [
"from galaxy_test.selenium.jupyter_context import init\n",
+ "\n",
"gx_selenium_context = init(config)"
]
},
@@ -67,6 +68,7 @@
"# optional step that shows how to access ActionChains\n",
"\n",
"from selenium.webdriver.common.action_chains import ActionChains\n",
+ "\n",
"ac = ActionChains(gx_selenium_context.driver)"
]
}
diff --git a/lib/galaxy_test/selenium/jupyter_context.py b/lib/galaxy_test/selenium/jupyter_context.py
index 759cdb3bcbf..5379a48d923 100644
--- a/lib/galaxy_test/selenium/jupyter_context.py
+++ b/lib/galaxy_test/selenium/jupyter_context.py
@@ -5,8 +5,6 @@ both Selenium for testing Galaxy with a browser and API populators for filling
in fixture data rapidly in the target Galaxy.
"""
-from typing import Optional
-
from galaxy.selenium.context import init as base_init
from galaxy.selenium.jupyter_context import JupyterContextImpl
from galaxy_test.base.api_util import get_admin_api_key
@@ -18,7 +16,7 @@ class JupyterTestContextImpl(JupyterContextImpl, GalaxyTestSeleniumContext):
# restarts needed during test building.
_interactive_components = True
- def __init__(self, from_dict: Optional[dict] = None) -> None:
+ def __init__(self, from_dict: dict | None = None) -> None:
from_dict = from_dict or {}
super().__init__(from_dict)
self.admin_api_key = from_dict.get("admin_api_key", get_admin_api_key())
diff --git a/lib/galaxy_test/selenium/test_tool_panel_search.py b/lib/galaxy_test/selenium/test_tool_panel_search.py
index a398eab5105..e0c8391ff69 100644
--- a/lib/galaxy_test/selenium/test_tool_panel_search.py
+++ b/lib/galaxy_test/selenium/test_tool_panel_search.py
@@ -98,10 +98,12 @@ class TestToolPanelSearchPlaywright(SeleniumTestCase):
"favorite order to persist after drag-and-drop",
)
self._wait_on(
- lambda: self._favorite_top_level_order()[:2]
- == [
- ("tags", "Text Manipulation"),
- ("tools", "cat1"),
- ],
+ lambda: (
+ self._favorite_top_level_order()[:2]
+ == [
+ ("tags", "Text Manipulation"),
+ ("tools", "cat1"),
+ ]
+ ),
"favorite tool panel order to update after drag-and-drop",
)
diff --git a/lib/galaxy_test/selenium/test_visualizations.py b/lib/galaxy_test/selenium/test_visualizations.py
index abf6b174bb4..eeb913f79b5 100644
--- a/lib/galaxy_test/selenium/test_visualizations.py
+++ b/lib/galaxy_test/selenium/test_visualizations.py
@@ -15,7 +15,6 @@ HG38_TITLE = "Human (GRCh38/hg38)"
class TestVisualizationsAnonymous(SeleniumTestCase):
-
@skip_without_datatype("png")
@skip_without_visualization_plugin("annotate_image")
@selenium_test
diff --git a/lib/galaxy_test/selenium/test_workflow_editor.py b/lib/galaxy_test/selenium/test_workflow_editor.py
index aa6b9209f63..2b8c099a017 100644
--- a/lib/galaxy_test/selenium/test_workflow_editor.py
+++ b/lib/galaxy_test/selenium/test_workflow_editor.py
@@ -1,7 +1,6 @@
import json
from typing import (
cast,
- Optional,
TYPE_CHECKING,
)
@@ -1810,7 +1809,7 @@ steps:
assert editor.tool_bar.selection_count.wait_for_visible().text.find("1 comment") != -1
- def create_and_wait_for_new_workflow_in_editor(self, annotation: Optional[str] = None) -> str:
+ def create_and_wait_for_new_workflow_in_editor(self, annotation: str | None = None) -> str:
editor = self.components.workflow_editor
name = self.workflow_create_new(annotation=annotation)
editor.canvas_body.wait_for_visible()
@@ -1845,7 +1844,7 @@ steps:
return (int(width_stripped), int(height_stripped))
@retry_assertion_during_transitions
- def assert_node_output_is(self, label: str, output_type: str, subcollection_type: Optional[str] = None):
+ def assert_node_output_is(self, label: str, output_type: str, subcollection_type: str | None = None):
editor = self.components.workflow_editor
node_label, output_name = label.split("#")
node = editor.node._(label=node_label)
diff --git a/lib/galaxy_test/selenium/test_workflow_extraction.py b/lib/galaxy_test/selenium/test_workflow_extraction.py
index 05d11f6f160..14db1ccd27b 100644
--- a/lib/galaxy_test/selenium/test_workflow_extraction.py
+++ b/lib/galaxy_test/selenium/test_workflow_extraction.py
@@ -6,7 +6,6 @@ reusing test setup infrastructure from API tests.
from typing import (
cast,
- Optional,
)
from galaxy_test.base.populators import skip_without_tool
@@ -60,7 +59,7 @@ class TestWorkflowExtractionSelenium(SeleniumTestCase, WorkflowStructureAssertio
self.dataset_populator.wait_for_history(history_id, assert_ok=True)
return hdca, job_ids_run1 + job_ids_run2
- def setup_copied_cat1_history(self, history_id: str) -> Optional[str]:
+ def setup_copied_cat1_history(self, history_id: str) -> str | None:
"""Run cat1 in one history, copy outputs to given history.
Returns: cat1 job_id associated with the copied datasets.
@@ -175,7 +174,7 @@ test_data:
workflow_id = self.find_workflow_by_name(name)
return self.workflow_populator.download_workflow(workflow_id)
- def extract_workflow_and_download(self, name: str, screenshot_name: Optional[str] = None) -> dict:
+ def extract_workflow_and_download(self, name: str, screenshot_name: str | None = None) -> dict:
"""Navigate to extraction, submit form, return downloaded workflow."""
self.navigate_to_workflow_extraction()
if screenshot_name:
diff --git a/lib/galaxy_test/selenium/upload_activity_helpers.py b/lib/galaxy_test/selenium/upload_activity_helpers.py
index 7a6c7a2edec..99434e3850f 100644
--- a/lib/galaxy_test/selenium/upload_activity_helpers.py
+++ b/lib/galaxy_test/selenium/upload_activity_helpers.py
@@ -27,7 +27,6 @@ from typing import (
overload,
TypedDict,
TypeVar,
- Union,
)
from .framework import NavigatesGalaxyMixin
@@ -146,11 +145,10 @@ class DataLibraryUploadItem(UploadItem):
class UploadContext:
-
def __init__(self, method_id: UploadMethodId, driver_wrapper: NavigatesGalaxyMixin):
self.driver_wrapper = driver_wrapper
self._item_count = 0
- self._current_method_id: Optional[UploadMethodId] = None
+ self._current_method_id: UploadMethodId | None = None
# Navigate to the upload method
self.driver_wrapper.home()
@@ -363,7 +361,7 @@ class UploadContext:
if option_id:
candidates.append((option_id, option_label))
- target_id: Optional[str] = None
+ target_id: str | None = None
for option_id, option_label in candidates:
if option_id.lower() == composite_type_lower or option_label.lower() == composite_type_lower:
target_id = option_id
@@ -539,13 +537,11 @@ class BaseUploadContext:
class LocalFileContext(BaseUploadContext):
-
def stage_local_file(self, test_path: str, metadata: Optional["UploadMetadata"] = None) -> LocalUploadItem:
return self._context.stage_local_file(test_path, metadata)
class PasteContentContext(BaseUploadContext):
-
def stage_paste_content(self, content: str, metadata: Optional["UploadMetadata"] = None) -> PasteContentUploadItem:
return self._context.stage_paste_content(content, metadata)
@@ -577,7 +573,6 @@ class PasteLinksContext(BaseUploadContext):
class RemoteFilesContext(BaseUploadContext):
-
def stage_remote_file(
self, source_label: str, file_label: str, metadata: Optional["UploadMetadata"] = None
) -> RemoteFileUploadItem:
@@ -585,7 +580,6 @@ class RemoteFilesContext(BaseUploadContext):
class CompositeFileContext(BaseUploadContext):
-
def select_composite(self, composite_type: str) -> "CompositeFileContext":
"""Select composite datatype in the composite-file method."""
self._context.select_composite(composite_type)
@@ -608,7 +602,6 @@ class CompositeFileContext(BaseUploadContext):
class DataLibraryContext(BaseUploadContext):
-
def stage_data_library_dataset(self, library_label: str, dataset_label: str) -> DataLibraryUploadItem:
return self._context.stage_data_library_dataset(library_label, dataset_label)
@@ -645,14 +638,16 @@ class UsesUploadActivity(NavigatesGalaxyMixin):
@overload
def upload_context(self, method_id: Literal["data-library"]) -> DataLibraryContext: ...
- def upload_context(self, method_id: UploadMethodId) -> Union[
- LocalFileContext,
- PasteContentContext,
- PasteLinksContext,
- RemoteFilesContext,
- CompositeFileContext,
- DataLibraryContext,
- ]:
+ def upload_context(
+ self, method_id: UploadMethodId
+ ) -> (
+ LocalFileContext
+ | PasteContentContext
+ | PasteLinksContext
+ | RemoteFilesContext
+ | CompositeFileContext
+ | DataLibraryContext
+ ):
"""Create an upload context for the specified method.
Args:
diff --git a/lib/tool_shed/context.py b/lib/tool_shed/context.py
index 9a813188305..1a486729c81 100644
--- a/lib/tool_shed/context.py
+++ b/lib/tool_shed/context.py
@@ -1,5 +1,4 @@
import abc
-from typing import Optional
from sqlalchemy.orm import scoped_session
from typing_extensions import Protocol
@@ -57,7 +56,7 @@ class ProvidesUserContext(ProvidesAppContext, Protocol):
@property
@abc.abstractmethod
- def user(self) -> Optional[User]:
+ def user(self) -> User | None:
"""Provide access to the user object."""
@property
@@ -84,7 +83,7 @@ class ProvidesRepositoriesContext(ProvidesUserContext, Protocol):
class SessionRequestContext(ProvidesRepositoriesContext, Protocol):
@abc.abstractmethod
- def get_galaxy_session(self) -> Optional[GalaxySession]: ...
+ def get_galaxy_session(self) -> GalaxySession | None: ...
@abc.abstractmethod
def set_galaxy_session(self, galaxy_session: GalaxySession): ...
@@ -107,16 +106,16 @@ class SessionRequestContext(ProvidesRepositoriesContext, Protocol):
class SessionRequestContextImpl(SessionRequestContext):
_app: ToolShedApp
- _user: Optional[User]
- _galaxy_session: Optional[GalaxySession]
+ _user: User | None
+ _galaxy_session: GalaxySession | None
def __init__(
self,
app: ToolShedApp,
request: GalaxyAbstractRequest,
response: GalaxyAbstractResponse,
- user: Optional[User] = None,
- galaxy_session: Optional[GalaxySession] = None,
+ user: User | None = None,
+ galaxy_session: GalaxySession | None = None,
url_builder=None,
):
self._app = app
@@ -135,10 +134,10 @@ class SessionRequestContextImpl(SessionRequestContext):
return self._url_builder
@property
- def user(self) -> Optional[User]:
+ def user(self) -> User | None:
return self._user
- def get_galaxy_session(self) -> Optional[GalaxySession]:
+ def get_galaxy_session(self) -> GalaxySession | None:
return self._galaxy_session
def set_galaxy_session(self, galaxy_session: GalaxySession):
@@ -175,7 +174,7 @@ class SessionRequestContextImpl(SessionRequestContext):
return token
@property
- def galaxy_session(self) -> Optional[GalaxySession]:
+ def galaxy_session(self) -> GalaxySession | None:
return self._galaxy_session
def log_event(self, str):
diff --git a/lib/tool_shed/dependencies/attribute_handlers.py b/lib/tool_shed/dependencies/attribute_handlers.py
index 2182d7ec17d..3e395abe480 100644
--- a/lib/tool_shed/dependencies/attribute_handlers.py
+++ b/lib/tool_shed/dependencies/attribute_handlers.py
@@ -1,7 +1,6 @@
import copy
import logging
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -224,9 +223,9 @@ class ToolDependencyAttributeHandler:
def _create_element(
tag: str,
- attributes: Optional[dict[str, str]] = None,
- sub_elements: Optional[dict[str, list[tuple[str, str]]]] = None,
-) -> Optional[Element]:
+ attributes: dict[str, str] | None = None,
+ sub_elements: dict[str, list[tuple[str, str]]] | None = None,
+) -> Element | None:
"""
Create a new element whose tag is the value of the received tag, and whose attributes are all
key / value pairs in the received attributes and sub_elements.
diff --git a/lib/tool_shed/dependencies/repository/relation_builder.py b/lib/tool_shed/dependencies/repository/relation_builder.py
index 2aa24303f42..2c7628073a5 100644
--- a/lib/tool_shed/dependencies/repository/relation_builder.py
+++ b/lib/tool_shed/dependencies/repository/relation_builder.py
@@ -1,7 +1,6 @@
import logging
from typing import (
Any,
- Optional,
TYPE_CHECKING,
)
@@ -164,7 +163,7 @@ class RelationBuilder:
This method ensures that all required repositories to the nth degree are returned.
"""
# Assume the current repository does not have repository dependencies defined for it.
- current_repository_key: Optional[str] = None
+ current_repository_key: str | None = None
if metadata := self.repository_metadata.metadata:
# The value of self.tool_shed_url must include the port, but doesn't have to include
# the protocol.
diff --git a/lib/tool_shed/managers/model_cache.py b/lib/tool_shed/managers/model_cache.py
index d780960fdf1..8bd3611744b 100644
--- a/lib/tool_shed/managers/model_cache.py
+++ b/lib/tool_shed/managers/model_cache.py
@@ -2,7 +2,6 @@ import json
import os
from typing import (
Any,
- Optional,
TypeVar,
)
@@ -42,7 +41,7 @@ class ModelCache:
cache_target = os.path.join(self._cache_directory, MODEL_HASHES[model_class], tool_id, tool_version)
return cache_target
- def get_cache_entry_for(self, model_class: type[M], tool_id: str, tool_version: str) -> Optional[M]:
+ def get_cache_entry_for(self, model_class: type[M], tool_id: str, tool_version: str) -> M | None:
cache_target = self._cache_target(model_class, tool_id, tool_version)
if not os.path.exists(cache_target):
return None
diff --git a/lib/tool_shed/managers/repositories.py b/lib/tool_shed/managers/repositories.py
index 3cd599c4591..6baead9f5c9 100644
--- a/lib/tool_shed/managers/repositories.py
+++ b/lib/tool_shed/managers/repositories.py
@@ -10,8 +10,6 @@ from time import strftime
from typing import (
Any,
cast,
- Optional,
- Union,
)
from pydantic import BaseModel
@@ -162,13 +160,13 @@ def deprecated_hostname() -> str:
class UpdatesRequest(BaseModel):
- name: Optional[str] = None
- owner: Optional[str] = None
+ name: str | None = None
+ owner: str | None = None
changeset_revision: str
hexlify: bool = True
-def check_updates(app: ToolShedApp, request: UpdatesRequest) -> Union[str, dict[str, Any]]:
+def check_updates(app: ToolShedApp, request: UpdatesRequest) -> str | dict[str, Any]:
name = request.name
owner = request.owner
changeset_revision = request.changeset_revision
@@ -244,7 +242,7 @@ def index_tool_ids(app: ToolShedApp, tool_ids: list[str]) -> dict[str, Any]:
continue
for changeset, changehash in repository.installable_revisions(app):
metadata = get_current_repository_metadata_for_changeset_revision(app, repository, changehash)
- tools: Optional[list[dict[str, Any]]] = metadata.metadata.get("tools")
+ tools: list[dict[str, Any]] | None = metadata.metadata.get("tools")
if not tools:
log.warning(f"Repository {owner}/{name}/{changehash} does not contain valid tools, skipping")
continue
@@ -280,11 +278,11 @@ def index_tool_ids(app: ToolShedApp, tool_ids: list[str]) -> dict[str, Any]:
class IndexRequest(BaseModel):
- name: Optional[str] = None
- owner: Optional[str] = None
+ name: str | None = None
+ owner: str | None = None
deleted: bool = False
- filter: Optional[str] = None
- category_id: Optional[str] = None
+ filter: str | None = None
+ category_id: str | None = None
sort_by: IndexSortByType = "name"
sort_desc: bool = False
@@ -413,7 +411,7 @@ def get_value_mapper(app: ToolShedApp) -> dict[str, Callable]:
def get_ordered_installable_revisions(
- app: ToolShedApp, name: Optional[str], owner: Optional[str], tsr_id: Optional[str]
+ app: ToolShedApp, name: str | None, owner: str | None, tsr_id: str | None
) -> list[str]:
eagerload_columns = [Repository.downloadable_revisions]
if None not in [name, owner]:
@@ -528,11 +526,11 @@ def reset_metadata_on_repository(
repository_id,
dry_run: bool = False,
verbose: bool = False,
- repository_clone_url: Optional[str] = None,
+ repository_clone_url: str | None = None,
) -> ResetMetadataOnRepositoryResponse:
app: ToolShedApp = trans.app
- def handle_repository(trans, start_time, repository, dry_run: bool, verbose: bool, clone_url: Optional[str] = None):
+ def handle_repository(trans, start_time, repository, dry_run: bool, verbose: bool, clone_url: str | None = None):
results: dict = dict(start_time=start_time, repository_status=[], dry_run=dry_run)
regenerated_metadata = {}
try:
@@ -711,7 +709,7 @@ def to_element_dict(app, repository: Repository, include_categories: bool = Fals
def repositories_by_category(
app: ToolShedApp,
category_id: str,
- page: Optional[int] = None,
+ page: int | None = None,
sort_key: str = "name",
sort_order: str = "asc",
installable: bool = True,
@@ -803,7 +801,7 @@ def upload_tar_and_set_metadata(
return message
-def ensure_can_manage(trans: ProvidesUserContext, repository: Repository, error_message: Optional[str] = None) -> None:
+def ensure_can_manage(trans: ProvidesUserContext, repository: Repository, error_message: str | None = None) -> None:
if not can_manage_repo(trans, repository):
error_message = error_message or "You do not have permission to update this repository."
raise InsufficientPermissionsException(error_message)
@@ -901,7 +899,7 @@ def remove_admin_user(app: ToolShedApp, repository: Repository, username: str) -
# ---------------------------------------------------------------------------
-def _has_galaxy_utilities(repository_metadata: Optional[RepositoryMetadata]) -> dict:
+def _has_galaxy_utilities(repository_metadata: RepositoryMetadata | None) -> dict:
"""Extract boolean flags describing what Galaxy utilities a repository revision contains."""
d = dict(
includes_data_managers=False,
@@ -1099,7 +1097,7 @@ def _get_repository_information(
)
-def get_required_repo_info_dict_from_encoded(trans: ProvidesRepositoriesContext, encoded_str: Optional[str]) -> dict:
+def get_required_repo_info_dict_from_encoded(trans: ProvidesRepositoriesContext, encoded_str: str | None) -> dict:
"""Decode an encoded string of repository dependency tuples and return installation info."""
repo_info_dict: dict = {}
if encoded_str:
diff --git a/lib/tool_shed/managers/tools.py b/lib/tool_shed/managers/tools.py
index c9437632c55..4d7437ce30c 100644
--- a/lib/tool_shed/managers/tools.py
+++ b/lib/tool_shed/managers/tools.py
@@ -1,9 +1,6 @@
import os
import tempfile
from collections import namedtuple
-from typing import (
- Optional,
-)
from galaxy import exceptions
from galaxy.exceptions import (
@@ -37,7 +34,7 @@ from tool_shed_client.schema import ShedParsedTool
from .repositories import get_repository_revision_metadata_model
from .trs import trs_tool_id_to_repository_metadata
-STOCK_TOOL_SOURCES: Optional[dict[str, dict[str, ToolSource]]] = None
+STOCK_TOOL_SOURCES: dict[str, dict[str, ToolSource]] | None = None
def search(trans: SessionRequestContext, q: str, page: int = 1, page_size: int = 10) -> dict:
@@ -100,7 +97,7 @@ def get_repository_metadata_tool_dict(
def parsed_tool_model_cached_for(
- trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
+ trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: str | None = None
) -> ShedParsedTool:
model_cache = trans.app.model_cache
parsed_tool = model_cache.get_cache_entry_for(ShedParsedTool, trs_tool_id, tool_version)
@@ -112,7 +109,7 @@ def parsed_tool_model_cached_for(
def parsed_tool_model_for(
- trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
+ trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: str | None = None
) -> ShedParsedTool:
tool_source, repository_metadata = tool_source_for(
trans, trs_tool_id, tool_version, repository_clone_url=repository_clone_url
@@ -127,8 +124,8 @@ def parsed_tool_model_for(
def tool_source_for(
- trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
-) -> tuple[ToolSource, Optional[RepositoryMetadata]]:
+ trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: str | None = None
+) -> tuple[ToolSource, RepositoryMetadata | None]:
if "~" in trs_tool_id:
return _shed_tool_source_for(trans, trs_tool_id, tool_version, repository_clone_url)
else:
@@ -139,7 +136,7 @@ def tool_source_for(
def _shed_tool_source_for(
- trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: Optional[str] = None
+ trans: ProvidesRepositoriesContext, trs_tool_id: str, tool_version: str, repository_clone_url: str | None = None
) -> tuple[ToolSource, RepositoryMetadata]:
rval = get_repository_metadata_tool_dict(trans, trs_tool_id, tool_version)
repository_metadata, tool_version_metadata = rval
@@ -171,7 +168,7 @@ def _shed_tool_source_for(
remove_dir(work_dir)
-def _stock_tool_source_for(tool_id: str, tool_version: str) -> Optional[ToolSource]:
+def _stock_tool_source_for(tool_id: str, tool_version: str) -> ToolSource | None:
_init_stock_tool_sources()
assert STOCK_TOOL_SOURCES
tool_version_sources = STOCK_TOOL_SOURCES.get(tool_id)
diff --git a/lib/tool_shed/managers/trs.py b/lib/tool_shed/managers/trs.py
index d2ba03ccd25..c5d86fe39db 100644
--- a/lib/tool_shed/managers/trs.py
+++ b/lib/tool_shed/managers/trs.py
@@ -1,7 +1,6 @@
from typing import (
Any,
cast,
- Optional,
)
from starlette.datastructures import URL
@@ -87,7 +86,7 @@ def get_repository_metadata_by_tool_version(
versions = {}
for _, changeset in repository.installable_revisions(app):
metadata = get_current_repository_metadata_for_changeset_revision(app, repository, changeset)
- tools: Optional[list[dict[str, Any]]] = metadata.metadata.get("tools")
+ tools: list[dict[str, Any]] | None = metadata.metadata.get("tools")
if not tools:
continue
for tool_metadata in tools:
@@ -98,7 +97,7 @@ def get_repository_metadata_by_tool_version(
def get_tools_for(repository_metadata: RepositoryMetadata) -> list[dict[str, Any]]:
- tools: Optional[list[dict[str, Any]]] = repository_metadata.metadata.get("tools")
+ tools: list[dict[str, Any]] | None = repository_metadata.metadata.get("tools")
assert tools
return tools
diff --git a/lib/tool_shed/metadata/repository_metadata_manager.py b/lib/tool_shed/metadata/repository_metadata_manager.py
index e7097a62cba..d88fc430c92 100644
--- a/lib/tool_shed/metadata/repository_metadata_manager.py
+++ b/lib/tool_shed/metadata/repository_metadata_manager.py
@@ -7,7 +7,6 @@ from dataclasses import (
from typing import (
Any,
Literal,
- Optional,
)
from sqlalchemy import (
@@ -52,7 +51,7 @@ log = logging.getLogger(__name__)
class ResetMetadataResult:
"""Result of reset_all_metadata_on_repository_in_tool_shed operation."""
- changeset_details: Optional[list[ChangesetMetadataStatus]] = None
+ changeset_details: list[ChangesetMetadataStatus] | None = None
# Regenerated metadata objects keyed by "{numeric_rev}:{changeset_hash}"
# These are the in-memory objects (possibly not persisted if dry_run=True)
regenerated_metadata: dict[str, RepositoryMetadata] = field(default_factory=dict)
@@ -62,20 +61,20 @@ class ToolShedMetadataGenerator(BaseMetadataGenerator):
"""A MetadataGenerator building on ToolShed's app and repository constructs."""
app: ToolShedApp
- repository: Optional[Repository] # type: ignore[assignment]
+ repository: Repository | None # type: ignore[assignment]
# why is mypy making me re-annotate these things from the base class, it didn't
# when they were in the same file
invalid_file_tups: list[InvalidFileT]
- repository_clone_url: Optional[str]
+ repository_clone_url: str | None
def __init__(
self,
trans: ProvidesRepositoriesContext,
- repository: Optional[Repository] = None,
- changeset_revision: Optional[str] = None,
- repository_clone_url: Optional[str] = None,
- shed_config_dict: Optional[dict[str, Any]] = None,
+ repository: Repository | None = None,
+ changeset_revision: str | None = None,
+ repository_clone_url: str | None = None,
+ shed_config_dict: dict[str, Any] | None = None,
relative_install_dir=None,
repository_files_dir=None,
resetting_all_metadata_on_repository=False,
@@ -120,7 +119,7 @@ class ToolShedMetadataGenerator(BaseMetadataGenerator):
return {}
def set_repository(
- self, repository, relative_install_dir: Optional[str] = None, changeset_revision: Optional[str] = None
+ self, repository, relative_install_dir: str | None = None, changeset_revision: str | None = None
):
self.repository = repository
if relative_install_dir is None and self.repository is not None:
@@ -486,7 +485,7 @@ class RepositoryMetadataManager(ToolShedMetadataGenerator):
def create_or_update_repository_metadata_with_details(
self, changeset_revision, metadata_dict, dry_run: bool = False
- ) -> tuple[Optional[RepositoryMetadata], Literal["created", "updated"]]:
+ ) -> tuple[RepositoryMetadata | None, Literal["created", "updated"]]:
"""Create or update a repository_metadata record in the tool shed.
Returns tuple of (repository_metadata, record_operation) where record_operation is:
@@ -832,7 +831,7 @@ class RepositoryMetadataManager(ToolShedMetadataGenerator):
# The list of changeset_revisions refers to repository_metadata records that have been created
# or updated. When the following loop completes, we'll delete all repository_metadata records
# for this repository that do not have a changeset_revision value in this list.
- changeset_revisions: list[Optional[str]] = []
+ changeset_revisions: list[str | None] = []
# Collect per-changeset details if verbose mode
changeset_details: list[ChangesetMetadataStatus] = []
# Collect regenerated metadata objects (keyed by changeset_revision hash)
@@ -1100,7 +1099,7 @@ class RepositoryMetadataManager(ToolShedMetadataGenerator):
return message, status
def set_repository(
- self, repository, relative_install_dir: Optional[str] = None, changeset_revision: Optional[str] = None
+ self, repository, relative_install_dir: str | None = None, changeset_revision: str | None = None
):
super().set_repository(repository)
self.repository_clone_url = relative_install_dir or common_util.generate_clone_url_for(self.trans, repository)
diff --git a/lib/tool_shed/test/base/api.py b/lib/tool_shed/test/base/api.py
index 7d7155bd30e..68801cfe680 100644
--- a/lib/tool_shed/test/base/api.py
+++ b/lib/tool_shed/test/base/api.py
@@ -1,7 +1,6 @@
import os
from typing import (
Any,
- Optional,
)
import pytest
@@ -25,7 +24,7 @@ from .populators import ToolShedPopulator
class ShedBaseTestCase(DrivenFunctionalTestCase):
- _populator: Optional[ToolShedPopulator] = None
+ _populator: ToolShedPopulator | None = None
@property
def populator(self) -> ToolShedPopulator:
@@ -102,7 +101,7 @@ class ShedGalaxyInteractorApi(GalaxyInteractorApi):
class ShedApiTestCase(ShedBaseTestCase, UsesShedApi):
- _galaxy_interactor: Optional[GalaxyInteractorApi] = None
+ _galaxy_interactor: GalaxyInteractorApi | None = None
@property
def galaxy_interactor(self) -> GalaxyInteractorApi:
diff --git a/lib/tool_shed/test/base/api_util.py b/lib/tool_shed/test/base/api_util.py
index ae84e29e96c..2a3f0b240d5 100644
--- a/lib/tool_shed/test/base/api_util.py
+++ b/lib/tool_shed/test/base/api_util.py
@@ -5,7 +5,6 @@ from functools import wraps
from typing import (
Any,
Literal,
- Optional,
)
from urllib.parse import urljoin
@@ -35,7 +34,7 @@ def get_admin_api_key() -> str:
return DEFAULT_TOOL_SHED_BOOTSTRAP_ADMIN_API_KEY
-def get_user_api_key() -> Optional[str]:
+def get_user_api_key() -> str | None:
"""Test user API key to use for functional tests.
If set, this should drive API based testing - if not set an admin API key will
@@ -115,9 +114,7 @@ def create_user(admin_interactor: ShedApiInteractor, user_dict: dict[str, Any],
return response.json()
-def ensure_user_with_email(
- admin_api_interactor: ShedApiInteractor, email: str, password: Optional[str]
-) -> dict[str, Any]:
+def ensure_user_with_email(admin_api_interactor: ShedApiInteractor, email: str, password: str | None) -> dict[str, Any]:
all_users_response = admin_api_interactor.get("users")
try:
all_users_response.raise_for_status()
diff --git a/lib/tool_shed/test/base/browser.py b/lib/tool_shed/test/base/browser.py
index 6a9f1b0046e..37a07b32917 100644
--- a/lib/tool_shed/test/base/browser.py
+++ b/lib/tool_shed/test/base/browser.py
@@ -1,9 +1,6 @@
import abc
-from typing import (
- Union,
-)
-FormValueType = Union[str, bool]
+FormValueType = str | bool
class ShedBrowser(metaclass=abc.ABCMeta):
diff --git a/lib/tool_shed/test/base/populators.py b/lib/tool_shed/test/base/populators.py
index ab8f7682b57..741cd197438 100644
--- a/lib/tool_shed/test/base/populators.py
+++ b/lib/tool_shed/test/base/populators.py
@@ -4,10 +4,6 @@ import tempfile
from collections.abc import Iterator
from pathlib import Path
from tempfile import NamedTemporaryFile
-from typing import (
- Optional,
- Union,
-)
import requests
from typing_extensions import Protocol
@@ -53,7 +49,7 @@ from .api_util import (
ShedApiInteractor,
)
-HasRepositoryId = Union[str, Repository]
+HasRepositoryId = str | Repository
DEFAULT_PREFIX = "repofortest"
TEST_DATA_REPO_FILES = resource_path(__name__, "../test_data")
@@ -81,7 +77,7 @@ def repo_tars(test_data_path: str) -> Iterator[Path]:
class HostsTestToolShed(Protocol):
host: str
- port: Optional[str]
+ port: str | None
class ToolShedPopulator:
@@ -96,9 +92,9 @@ class ToolShedPopulator:
def setup_bismark_repo(
self,
- repository_id: Optional[HasRepositoryId] = None,
- end: Optional[int] = None,
- category_id: Optional[str] = None,
+ repository_id: HasRepositoryId | None = None,
+ end: int | None = None,
+ category_id: str | None = None,
) -> HasRepositoryId:
if repository_id is None:
category_id = category_id or self.new_category(prefix="testbismark").id
@@ -108,10 +104,10 @@ class ToolShedPopulator:
def setup_test_data_repo_by_id(
self,
test_data_path: str,
- repository_id: Optional[HasRepositoryId] = None,
+ repository_id: HasRepositoryId | None = None,
assert_ok=True,
start: int = 0,
- end: Optional[int] = None,
+ end: int | None = None,
) -> HasRepositoryId:
if repository_id is None:
prefix = test_data_path.replace("_", "")
@@ -138,11 +134,11 @@ class ToolShedPopulator:
def setup_test_data_repo(
self,
test_data_path: str,
- repository: Optional[Repository] = None,
+ repository: Repository | None = None,
assert_ok=True,
start: int = 0,
- end: Optional[int] = None,
- category_id: Optional[str] = None,
+ end: int | None = None,
+ category_id: str | None = None,
) -> Repository:
if repository is None:
prefix = test_data_path.replace("_", "")
@@ -155,7 +151,7 @@ class ToolShedPopulator:
def setup_column_maker_repo(
self,
prefix=DEFAULT_PREFIX,
- category_id: Optional[str] = None,
+ category_id: str | None = None,
) -> Repository:
if category_id is None:
category_id = self.new_category(prefix=prefix).id
@@ -244,7 +240,7 @@ class ToolShedPopulator:
api_asserts.assert_status_code_is_ok(response)
return RepositoryUpdate(root=response.json())
- def new_repository(self, category_ids: Union[list[str], str], prefix: str = DEFAULT_PREFIX) -> Repository:
+ def new_repository(self, category_ids: list[str] | str, prefix: str = DEFAULT_PREFIX) -> Repository:
name = random_name(prefix=prefix)
synopsis = random_name(prefix=prefix)
request = CreateRepositoryRequest(
@@ -264,9 +260,7 @@ class ToolShedPopulator:
index_response.raise_for_status()
return BuildSearchIndexResponse(**index_response.json())
- def new_category(
- self, name: Optional[str] = None, description: Optional[str] = None, prefix=DEFAULT_PREFIX
- ) -> Category:
+ def new_category(self, name: str | None = None, description: str | None = None, prefix=DEFAULT_PREFIX) -> Category:
category_name = name or random_name(prefix=prefix)
category_description = description or "testcreaterepo"
request = CreateCategoryRequest(name=category_name, description=category_description)
@@ -313,7 +307,7 @@ class ToolShedPopulator:
actual_n = len(revisions.root)
assert actual_n == n, f"Expected {n} repository revisions, found {actual_n} for {repository}"
- def get_repository_for(self, owner: str, name: str, deleted: str = "false") -> Optional[Repository]:
+ def get_repository_for(self, owner: str, name: str, deleted: str = "false") -> Repository | None:
request = RepositoryIndexRequest(
owner=owner,
name=name,
@@ -322,13 +316,13 @@ class ToolShedPopulator:
index = self.repository_index(request)
return index.root[0] if index.root else None
- def repository_index(self, request: Optional[RepositoryIndexRequest]) -> RepositoryIndexResponse:
+ def repository_index(self, request: RepositoryIndexRequest | None) -> RepositoryIndexResponse:
repository_response = self._api_interactor.get("repositories", params=(request.model_dump() if request else {}))
api_asserts.assert_status_code_is_ok(repository_response)
return RepositoryIndexResponse(root=repository_response.json())
def repository_index_paginated(
- self, request: Optional[RepositoryPaginatedIndexRequest]
+ self, request: RepositoryPaginatedIndexRequest | None
) -> PaginatedRepositoryIndexResults:
repository_response = self._api_interactor.get(
"repositories", params=(request.model_dump() if request else {"page": 1})
@@ -455,7 +449,7 @@ class ToolShedPopulator:
return ToolSearchResults(**search_response.json())
def tool_guid(
- self, shed_host: HostsTestToolShed, repository: Repository, tool_id: str, tool_version: Optional[str] = None
+ self, shed_host: HostsTestToolShed, repository: Repository, tool_id: str, tool_version: str | None = None
) -> str:
owner = repository.owner
name = repository.name
diff --git a/lib/tool_shed/test/base/testcase.py b/lib/tool_shed/test/base/testcase.py
index 0299ce3d52e..d7fd470df5c 100644
--- a/lib/tool_shed/test/base/testcase.py
+++ b/lib/tool_shed/test/base/testcase.py
@@ -15,7 +15,6 @@ from typing import (
cast,
Optional,
TYPE_CHECKING,
- Union,
)
from urllib.parse import (
quote_plus,
@@ -125,7 +124,7 @@ class ToolShedInstallationClient(metaclass=abc.ABCMeta):
changeset_revision: str,
install_tool_dependencies: bool,
install_repository_dependencies: bool,
- new_tool_panel_section_label: Optional[str],
+ new_tool_panel_section_label: str | None,
) -> None:
""""""
@@ -179,8 +178,8 @@ class ToolShedInstallationClient(metaclass=abc.ABCMeta):
@abc.abstractmethod
def get_installed_repository_for(
- self, owner: Optional[str] = None, name: Optional[str] = None, changeset: Optional[str] = None
- ) -> Optional[dict[str, Any]]:
+ self, owner: str | None = None, name: str | None = None, changeset: str | None = None
+ ) -> dict[str, Any] | None:
""""""
@abc.abstractmethod
@@ -268,7 +267,7 @@ class GalaxyInteractorToolShedInstallationClient(ToolShedInstallationClient):
changeset_revision: str,
install_tool_dependencies: bool,
install_repository_dependencies: bool,
- new_tool_panel_section_label: Optional[str],
+ new_tool_panel_section_label: str | None,
):
payload = {
"tool_shed_url": self.testcase.url,
@@ -380,8 +379,8 @@ class GalaxyInteractorToolShedInstallationClient(ToolShedInstallationClient):
)
def get_installed_repository_for(
- self, owner: Optional[str] = None, name: Optional[str] = None, changeset: Optional[str] = None
- ) -> Optional[dict[str, Any]]:
+ self, owner: str | None = None, name: str | None = None, changeset: str | None = None
+ ) -> dict[str, Any] | None:
return self.testcase.get_installed_repository_for(owner=owner, name=name, changeset=changeset)
def get_all_installed_repositories(self) -> list[galaxy_model.ToolShedRepository]:
@@ -505,7 +504,7 @@ class StandaloneToolShedInstallationClient(ToolShedInstallationClient):
changeset_revision: str,
install_tool_dependencies: bool,
install_repository_dependencies: bool,
- new_tool_panel_section_label: Optional[str],
+ new_tool_panel_section_label: str | None,
):
tool_shed_url = self.testcase.url
payload = {
@@ -584,8 +583,8 @@ class StandaloneToolShedInstallationClient(ToolShedInstallationClient):
)
def get_installed_repository_for(
- self, owner: Optional[str] = None, name: Optional[str] = None, changeset: Optional[str] = None
- ) -> Optional[dict[str, Any]]:
+ self, owner: str | None = None, name: str | None = None, changeset: str | None = None
+ ) -> dict[str, Any] | None:
repository = get_installed_repository(self._installation_target.install_model.context, name, owner, changeset)
if repository:
return repository.to_dict()
@@ -623,8 +622,8 @@ class ShedTestCase(ShedApiTestCase):
"""Class of FunctionalTestCase geared toward HTML interactions using the Twill library."""
requires_galaxy: bool = False
- _installation_client: Optional[ToolShedInstallationClient] = None
- __browser: Optional[ShedBrowser] = None
+ _installation_client: ToolShedInstallationClient | None = None
+ __browser: ShedBrowser | None = None
_logged_in_populator: Optional["ToolShedPopulator"] = None
def setUp(self):
@@ -642,9 +641,9 @@ class ShedTestCase(ShedApiTestCase):
if os.environ.get("TOOL_SHED_TEST_INSTALL_CLIENT") == "standalone":
# TODO: once nose is out of the way - try to get away without
# instantiating the unused Galaxy server here.
- installation_client_class: Union[
- type[StandaloneToolShedInstallationClient], type[GalaxyInteractorToolShedInstallationClient]
- ] = StandaloneToolShedInstallationClient
+ installation_client_class: (
+ type[StandaloneToolShedInstallationClient] | type[GalaxyInteractorToolShedInstallationClient]
+ ) = StandaloneToolShedInstallationClient
full_stack_galaxy = False
else:
installation_client_class = GalaxyInteractorToolShedInstallationClient
@@ -683,7 +682,7 @@ class ShedTestCase(ShedApiTestCase):
self._browser.check_string_not_in_page(patt)
# Functions associated with user accounts
- def _submit_register_form(self, email: str, password: str, username: str, redirect: Optional[str] = None):
+ def _submit_register_form(self, email: str, password: str, username: str, redirect: str | None = None):
self._browser.fill_form_value("registration", "email", email)
if redirect is not None:
self._browser.fill_form_value("registration", "redirect", redirect)
@@ -702,7 +701,7 @@ class ShedTestCase(ShedApiTestCase):
email: str = "test@bx.psu.edu",
password: str = "testuser",
username: str = "admin-user",
- redirect: Optional[str] = None,
+ redirect: str | None = None,
) -> tuple[bool, bool, bool]:
return self._ensure_user_via_api(email, password, username)
@@ -739,7 +738,7 @@ class ShedTestCase(ShedApiTestCase):
email: str = "test@bx.psu.edu",
password: str = "testuser",
username: str = "admin-user",
- redirect: Optional[str] = None,
+ redirect: str | None = None,
logout_first: bool = True,
explicit_logout: bool = False,
):
@@ -829,7 +828,7 @@ class ShedTestCase(ShedApiTestCase):
url += f"?{urlencode(params)}"
return url
- def visit_url(self, url: str, params=None, allowed_codes: Optional[list[int]] = None) -> str:
+ def visit_url(self, url: str, params=None, allowed_codes: list[int] | None = None) -> str:
parsed_url = urlparse(url)
if len(parsed_url.netloc) == 0:
url = f"http://{self.host}:{self.port}{parsed_url.path}"
@@ -957,7 +956,7 @@ class ShedTestCase(ShedApiTestCase):
# each tool via /repository/load_invalid_tool. That Mako route is being removed.
# The metadata only stores which tool configs are invalid, not the error messages.
- def check_string_count_in_page(self, pattern, min_count: int, max_count: Optional[int] = None):
+ def check_string_count_in_page(self, pattern, min_count: int, max_count: int | None = None):
"""Checks the number of 'pattern' occurrences in the current browser page"""
page = self.last_page()
pattern_count = page.count(pattern)
@@ -1092,9 +1091,9 @@ class ShedTestCase(ShedApiTestCase):
self,
repository: Repository,
source: str,
- target: Optional[str] = None,
+ target: str | None = None,
strings_displayed=None,
- commit_message: Optional[str] = None,
+ commit_message: str | None = None,
):
with self.cloned_repo(repository) as temp_directory:
if target is None:
@@ -1461,9 +1460,9 @@ class ShedTestCase(ShedApiTestCase):
category_name: str,
install_tool_dependencies: bool = False,
install_repository_dependencies: bool = True,
- changeset_revision: Optional[str] = None,
- preview_strings_displayed: Optional[list[str]] = None,
- new_tool_panel_section_label: Optional[str] = None,
+ changeset_revision: str | None = None,
+ preview_strings_displayed: list[str] | None = None,
+ new_tool_panel_section_label: str | None = None,
) -> None:
self.browse_tool_shed(url=self.url)
category = self.populator.get_category_with_name(category_name)
@@ -1538,7 +1537,7 @@ class ShedTestCase(ShedApiTestCase):
self,
name: str,
owner: str,
- changeset_revision: Optional[str] = None,
+ changeset_revision: str | None = None,
strings_displayed=None,
strings_not_displayed=None,
):
@@ -1745,7 +1744,7 @@ class ShedTestCase(ShedApiTestCase):
return self._installation_client.get_installed_repositories_by_name_owner(repository_name, repository_owner)
def _get_installed_repository_for(
- self, owner: Optional[str] = None, name: Optional[str] = None, changeset: Optional[str] = None
+ self, owner: str | None = None, name: str | None = None, changeset: str | None = None
):
assert self._installation_client
return self._installation_client.get_installed_repository_for(owner=owner, name=name, changeset=changeset)
@@ -1783,7 +1782,7 @@ class ShedTestCase(ShedApiTestCase):
self,
installed_repository: galaxy_model.ToolShedRepository,
repository_name: str,
- changeset: Optional[str] = None,
+ changeset: str | None = None,
) -> None:
json = self.display_installed_repository_manage_json(installed_repository)
if "repository_dependencies" not in json:
diff --git a/lib/tool_shed/test/functional/test_shed_galaxy_install_apis.py b/lib/tool_shed/test/functional/test_shed_galaxy_install_apis.py
index eedd2cc96ca..0678016efca 100644
--- a/lib/tool_shed/test/functional/test_shed_galaxy_install_apis.py
+++ b/lib/tool_shed/test/functional/test_shed_galaxy_install_apis.py
@@ -566,8 +566,7 @@ class TestGalaxyInstallApis(ShedApiTestCase):
self._repo_params(repository, first_changeset),
)
api_asserts.assert_status_code_is_ok(updated_response)
- updated_text = updated_response.text.strip()
- if updated_text:
+ if updated_text := updated_response.text.strip():
updated_revisions = updated_text.split(",")
# The next installable should be reachable from the update path
assert next_rev in updated_revisions
diff --git a/lib/tool_shed/util/commit_util.py b/lib/tool_shed/util/commit_util.py
index 0e19b31cc86..72ea5d01549 100644
--- a/lib/tool_shed/util/commit_util.py
+++ b/lib/tool_shed/util/commit_util.py
@@ -7,9 +7,7 @@ import shutil
import tempfile
from collections import namedtuple
from typing import (
- Optional,
TYPE_CHECKING,
- Union,
)
from sqlalchemy import select
@@ -157,7 +155,7 @@ def handle_bz2(repository: "Repository", uploaded_file_name):
shutil.move(uncompressed.name, uploaded_file_name)
-ChangeResponseT = tuple[Union[bool, str], str, list[str], str, int, int]
+ChangeResponseT = tuple[bool | str, str, list[str], str, int, int]
def handle_directory_changes(
@@ -172,7 +170,7 @@ def handle_directory_changes(
commit_message: str,
undesirable_dirs_removed: int,
undesirable_files_removed: int,
- repo_path: Optional[str] = None,
+ repo_path: str | None = None,
dry_run: bool = False,
) -> ChangeResponseT:
repo_path = repo_path or repository.repo_path(app)
diff --git a/lib/tool_shed/util/common_util.py b/lib/tool_shed/util/common_util.py
index 81c995a3733..68727c652f5 100644
--- a/lib/tool_shed/util/common_util.py
+++ b/lib/tool_shed/util/common_util.py
@@ -36,7 +36,7 @@ def generate_clone_url_for(trans: "ProvidesRepositoriesContext", repository: "Re
def generate_clone_url_for_repository_in_tool_shed(
- user: Optional["User"], repository: "Repository", hostname: Optional[str] = None
+ user: Optional["User"], repository: "Repository", hostname: str | None = None
) -> str:
"""Generate the URL for cloning a repository that is in the tool shed."""
base_url = hostname or url_for("/", qualified=True).rstrip("/")
diff --git a/lib/tool_shed/util/metadata_util.py b/lib/tool_shed/util/metadata_util.py
index f4053f5720e..95a7816dde2 100644
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -1,7 +1,6 @@
import logging
from operator import itemgetter
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -268,7 +267,7 @@ def get_repository_dependency_tups_from_repository_metadata(
def get_repository_metadata_by_changeset_revision(
app: "ToolShedApp", id: str, changeset_revision: str
-) -> Optional[RepositoryMetadata]:
+) -> RepositoryMetadata | None:
"""Get metadata for a specified repository change set from the database."""
decoded_id = app.security.decode_id(id)
return repository_metadata_by_changeset_revision(app.model, decoded_id, changeset_revision)
@@ -276,7 +275,7 @@ def get_repository_metadata_by_changeset_revision(
def repository_metadata_by_changeset_revision(
model_mapping: "ToolShedModelMapping", id: int, changeset_revision: str
-) -> Optional[RepositoryMetadata]:
+) -> RepositoryMetadata | None:
# Make sure there are no duplicate records, and return the single unique record for the changeset_revision.
# Duplicate records were somehow created in the past. The cause of this issue has been resolved, but we'll
# leave this method as is for a while longer to ensure all duplicate records are removed.
diff --git a/lib/tool_shed/util/repository_content_util.py b/lib/tool_shed/util/repository_content_util.py
index 8a3202a51d2..ba3a2115a35 100644
--- a/lib/tool_shed/util/repository_content_util.py
+++ b/lib/tool_shed/util/repository_content_util.py
@@ -2,7 +2,6 @@ import os
import shutil
import tempfile
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -34,8 +33,8 @@ def upload_tar(
dry_run: bool = False,
remove_repo_files_not_in_tar: bool = True,
new_repo_alert: bool = False,
- rdah: Optional[RepositoryDependencyAttributeHandler] = None,
- tdah: Optional[ToolDependencyAttributeHandler] = None,
+ rdah: RepositoryDependencyAttributeHandler | None = None,
+ tdah: ToolDependencyAttributeHandler | None = None,
) -> ChangeResponseT:
host = trans.repositories_hostname
app = trans.app
diff --git a/lib/tool_shed/util/repository_util.py b/lib/tool_shed/util/repository_util.py
index dbd7075830b..0086d14a359 100644
--- a/lib/tool_shed/util/repository_util.py
+++ b/lib/tool_shed/util/repository_util.py
@@ -4,7 +4,6 @@ import os
import re
import tempfile
from typing import (
- Optional,
TYPE_CHECKING,
)
@@ -195,7 +194,7 @@ def create_repository(
description,
long_description,
user,
- category_ids: Optional[list[str]] = None,
+ category_ids: list[str] | None = None,
remote_repository_url=None,
homepage_url=None,
) -> tuple[model.Repository, str]:
@@ -246,7 +245,7 @@ def create_repository(
def generate_sharable_link_for_repository_in_tool_shed(
- repository: model.Repository, changeset_revision: Optional[str] = None, base_url: Optional[str] = None
+ repository: model.Repository, changeset_revision: str | None = None, base_url: str | None = None
) -> str:
"""Generate the URL for sharing a repository that is in the tool shed."""
if base_url is None:
@@ -339,7 +338,7 @@ def get_repositories_by_category(
installable: bool = False,
sort_order="asc",
sort_key="name",
- page: Optional[int] = None,
+ page: int | None = None,
per_page: int = 25,
):
repositories = []
@@ -432,9 +431,7 @@ def change_repository_name_in_hgrc_file(hgrc_file: str, new_name: str) -> None:
config.write(fh)
-def update_repository(
- trans: "ProvidesUserContext", id: str, **kwds
-) -> tuple[Optional[model.Repository], Optional[str]]:
+def update_repository(trans: "ProvidesUserContext", id: str, **kwds) -> tuple[model.Repository | None, str | None]:
"""Update an existing ToolShed repository"""
app = trans.app
sa_session = app.model.session
@@ -451,7 +448,7 @@ def update_repository(
def update_validated_repository(
trans: "ProvidesUserContext", repository: model.Repository, **kwds
-) -> tuple[Optional[model.Repository], Optional[str]]:
+) -> tuple[model.Repository | None, str | None]:
"""Update an existing ToolShed repository metadata once permissions have been checked."""
app = trans.app
sa_session = app.model.session
@@ -466,7 +463,6 @@ def update_validated_repository(
flush_needed = True
if "category_ids" in kwds and isinstance(kwds["category_ids"], list):
-
# Remove existing category associations
_delete_repository_category_associations(sa_session, model.RepositoryCategoryAssociation, repository.id)
@@ -546,7 +542,7 @@ def get_repositories(
installable: bool,
sort_order,
sort_key,
- page: Optional[int],
+ page: int | None,
per_page: int,
):
stmt = (
diff --git a/lib/tool_shed/webapp/api2/__init__.py b/lib/tool_shed/webapp/api2/__init__.py
index 29d867dd4c7..bf30152de0f 100644
--- a/lib/tool_shed/webapp/api2/__init__.py
+++ b/lib/tool_shed/webapp/api2/__init__.py
@@ -3,7 +3,6 @@ from collections.abc import AsyncGenerator
from json import JSONDecodeError
from typing import (
cast,
- Optional,
TypeVar,
)
@@ -86,7 +85,7 @@ def get_api_user(
user_manager: UserManager = depends(UserManager),
key: str = Security(api_key_query),
x_api_key: str = Security(api_key_header),
-) -> Optional[User]:
+) -> User | None:
api_key = key or x_api_key
if not api_key:
return None
@@ -103,7 +102,7 @@ def get_session(
session_manager=cast(GalaxySessionManager, Depends(get_session_manager)),
security: IdEncodingHelper = depends(IdEncodingHelper),
galaxysession: str = Security(api_key_cookie),
-) -> Optional[GalaxySession]:
+) -> GalaxySession | None:
if galaxysession:
session_key = security.decode_guid(galaxysession)
if session_key:
@@ -113,9 +112,9 @@ def get_session(
def get_user(
- galaxy_session=cast(Optional[GalaxySession], Depends(get_session)),
- api_user=cast(Optional[User], Depends(get_api_user)),
-) -> Optional[User]:
+ galaxy_session=cast(GalaxySession | None, Depends(get_session)),
+ api_user=cast(User | None, Depends(get_api_user)),
+) -> User | None:
if galaxy_session:
return galaxy_session.user
return api_user
@@ -125,8 +124,8 @@ def get_trans(
request: Request,
response: Response,
app: ToolShedApp = DependsOnApp,
- user=cast(Optional[User], Depends(get_user)),
- galaxy_session=cast(Optional[GalaxySession], Depends(get_session)),
+ user=cast(User | None, Depends(get_user)),
+ galaxy_session=cast(GalaxySession | None, Depends(get_session)),
) -> SessionRequestContext:
url_builder = UrlBuilder(request)
galaxy_request = GalaxyASGIRequest(request)
@@ -214,7 +213,7 @@ ChangesetRevisionPathParam: str = Path(
UsernameIdPathParam: str = Path(..., title="Username", description="The target username.")
-CommitMessageQueryParam: Optional[str] = Query(
+CommitMessageQueryParam: str | None = Query(
default=None,
title="Commit Message",
description="Set commit message as a query parameter.",
@@ -232,13 +231,13 @@ CommitMessage: str = Query(
description="A commit message to store with repository update.",
)
-RepositoryIndexQueryParam: Optional[str] = Query(
+RepositoryIndexQueryParam: str | None = Query(
default=None,
title="Search Query",
description="This will perform a full search with whoosh on the backend and will cause the API endpoint to return a RepositorySearchResult. This should not be used with the 'filter' parameter.",
)
-RepositoryIndexFilterParam: Optional[str] = Query(
+RepositoryIndexFilterParam: str | None = Query(
default=None,
title="Filter Text",
description="This will perform a quick search using database operators. This should not be used with the 'q' parameter.",
@@ -268,7 +267,7 @@ ToolSearchPageQueryParam: int = Query(
description="",
)
-RepositorySearchPageQueryParam: Optional[int] = Query(
+RepositorySearchPageQueryParam: int | None = Query(
default=None,
title="Page",
description="",
@@ -279,24 +278,24 @@ RepositorySearchPageSizeQueryParam: int = Query(
title="Page Size",
)
-RepositoryIndexDeletedQueryParam: Optional[bool] = Query(False, title="Deleted?")
+RepositoryIndexDeletedQueryParam: bool | None = Query(False, title="Deleted?")
-RepositoryIndexOwnerQueryParam: Optional[str] = Query(None, title="Owner")
+RepositoryIndexOwnerQueryParam: str | None = Query(None, title="Owner")
-RepositoryIndexNameQueryParam: Optional[str] = Query(None, title="Name")
+RepositoryIndexNameQueryParam: str | None = Query(None, title="Name")
-RepositoryIndexCategoryQueryParam: Optional[str] = Query(None, title="Category ID")
+RepositoryIndexCategoryQueryParam: str | None = Query(None, title="Category ID")
-RepositoryIndexToolIdsQueryParam: Optional[list[str]] = Query(
+RepositoryIndexToolIdsQueryParam: list[str] | None = Query(
None, title="Tool IDs", description="List of tool GUIDs to find the repository for"
)
-OptionalRepositoryOwnerParam: Optional[str] = Query(None, title="Owner")
-OptionalRepositoryNameParam: Optional[str] = Query(None, title="Name")
+OptionalRepositoryOwnerParam: str | None = Query(None, title="Owner")
+OptionalRepositoryNameParam: str | None = Query(None, title="Name")
RequiredRepositoryChangesetRevisionParam: str = Query(..., title="Changeset Revision")
-OptionalRepositoryIdParam: Optional[str] = Query(None, title="TSR ID")
-OptionalHexlifyParam: Optional[bool] = Query(True, title="Hexlify response")
+OptionalRepositoryIdParam: str | None = Query(None, title="TSR ID")
+OptionalHexlifyParam: bool | None = Query(True, title="Hexlify response")
DryRunQueryParam: bool = Query(False, title="Dry Run", description="Preview changes without persisting to database")
VerboseQueryParam: bool = Query(False, title="Verbose", description="Return detailed per-changeset information")
@@ -307,7 +306,7 @@ CategoryIdPathParam: str = Path(
CategoryRepositoriesInstallableQueryParam: bool = Query(False, title="Installable?")
CategoryRepositoriesSortKeyQueryParam: str = Query("name", title="Sort Key")
CategoryRepositoriesSortOrderQueryParam: str = Query("asc", title="Sort Order")
-CategoryRepositoriesPageQueryParam: Optional[int] = Query(None, title="Page")
+CategoryRepositoriesPageQueryParam: int | None = Query(None, title="Page")
FromTipQueryParam: bool = Query(
default=False,
@@ -335,7 +334,7 @@ def ensure_valid_session(trans: SessionRequestContext) -> None:
# in the most common case (session exists and is valid).
galaxy_session_requires_flush = False
if secure_id := request.get_cookie(AUTH_COOKIE_NAME):
- session_key: Optional[str] = app.security.decode_guid(secure_id)
+ session_key: str | None = app.security.decode_guid(secure_id)
if session_key:
# We do NOT catch exceptions here, if the database is down the request should fail,
# and we should not generate a new session.
@@ -379,7 +378,7 @@ def set_cookie(trans: SessionRequestContext, value: str, key, path="/", age=90)
"""Convenience method for setting a session cookie"""
# In wsgi we were setting both a max_age and and expires, but
# all browsers support max_age now.
- domain: Optional[str] = trans.app.config.cookie_domain
+ domain: str | None = trans.app.config.cookie_domain
trans.response.set_cookie(
key,
unicodify(value),
diff --git a/lib/tool_shed/webapp/api2/categories.py b/lib/tool_shed/webapp/api2/categories.py
index de6f03204cf..0fb0992006e 100644
--- a/lib/tool_shed/webapp/api2/categories.py
+++ b/lib/tool_shed/webapp/api2/categories.py
@@ -1,7 +1,3 @@
-from typing import (
- Optional,
-)
-
from fastapi import Body
from tool_shed.context import SessionRequestContext
@@ -79,7 +75,7 @@ class FastAPICategories:
installable: bool = CategoryRepositoriesInstallableQueryParam,
sort_key: str = CategoryRepositoriesSortKeyQueryParam,
sort_order: str = CategoryRepositoriesSortOrderQueryParam,
- page: Optional[int] = CategoryRepositoriesPageQueryParam,
+ page: int | None = CategoryRepositoriesPageQueryParam,
) -> RepositoriesByCategory:
return repositories_by_category(
trans.app,
diff --git a/lib/tool_shed/webapp/api2/repositories.py b/lib/tool_shed/webapp/api2/repositories.py
index 6c00fdea005..148d871cbfd 100644
--- a/lib/tool_shed/webapp/api2/repositories.py
+++ b/lib/tool_shed/webapp/api2/repositories.py
@@ -5,8 +5,6 @@ import tempfile
from typing import (
cast,
IO,
- Optional,
- Union,
)
from fastapi import (
@@ -115,7 +113,7 @@ log = logging.getLogger(__name__)
router = Router(tags=["repositories"])
-IndexResponse = Union[RepositorySearchResults, list[Repository], PaginatedRepositoryIndexResults]
+IndexResponse = RepositorySearchResults | list[Repository] | PaginatedRepositoryIndexResults
@as_form
@@ -134,16 +132,16 @@ class FastAPIRepositories:
)
def index(
self,
- q: Optional[str] = RepositoryIndexQueryParam,
- filter: Optional[str] = RepositoryIndexFilterParam,
- page: Optional[int] = RepositorySearchPageQueryParam,
- page_size: Optional[int] = RepositorySearchPageSizeQueryParam,
- deleted: Optional[bool] = RepositoryIndexDeletedQueryParam,
- owner: Optional[str] = RepositoryIndexOwnerQueryParam,
- name: Optional[str] = RepositoryIndexNameQueryParam,
- category_id: Optional[str] = RepositoryIndexCategoryQueryParam,
- sort_desc: Optional[bool] = RepositoryIndexSortDescParam,
- sort_by: Optional[IndexSortByType] = RepositoryIndexSortByParam,
+ q: str | None = RepositoryIndexQueryParam,
+ filter: str | None = RepositoryIndexFilterParam,
+ page: int | None = RepositorySearchPageQueryParam,
+ page_size: int | None = RepositorySearchPageSizeQueryParam,
+ deleted: bool | None = RepositoryIndexDeletedQueryParam,
+ owner: str | None = RepositoryIndexOwnerQueryParam,
+ name: str | None = RepositoryIndexNameQueryParam,
+ category_id: str | None = RepositoryIndexCategoryQueryParam,
+ sort_desc: bool | None = RepositoryIndexSortDescParam,
+ sort_by: IndexSortByType | None = RepositoryIndexSortByParam,
trans: SessionRequestContext = DependsOnTrans,
) -> IndexResponse:
@@ -274,9 +272,9 @@ class FastAPIRepositories:
)
def get_ordered_installable_revisions(
self,
- owner: Optional[str] = OptionalRepositoryOwnerParam,
- name: Optional[str] = OptionalRepositoryNameParam,
- tsr_id: Optional[str] = OptionalRepositoryIdParam,
+ owner: str | None = OptionalRepositoryOwnerParam,
+ name: str | None = OptionalRepositoryNameParam,
+ tsr_id: str | None = OptionalRepositoryIdParam,
) -> list[str]:
return get_ordered_installable_revisions(self.app, name, owner, tsr_id)
@@ -333,10 +331,10 @@ class FastAPIRepositories:
)
def updates(
self,
- owner: Optional[str] = OptionalRepositoryOwnerParam,
- name: Optional[str] = OptionalRepositoryNameParam,
+ owner: str | None = OptionalRepositoryOwnerParam,
+ name: str | None = OptionalRepositoryNameParam,
changeset_revision: str = RequiredRepositoryChangesetRevisionParam,
- hexlify: Optional[bool] = OptionalHexlifyParam,
+ hexlify: bool | None = OptionalHexlifyParam,
):
request = UpdatesRequest(
name=name,
@@ -579,9 +577,9 @@ class FastAPIRepositories:
self,
request: Request,
encoded_repository_id: str = RepositoryIdPathParam,
- commit_message: Optional[str] = CommitMessageQueryParam,
+ commit_message: str | None = CommitMessageQueryParam,
trans: SessionRequestContext = DependsOnTrans,
- files: Optional[list[UploadFile]] = None,
+ files: list[UploadFile] | None = None,
revision_request: RepositoryUpdateRequest = Depends(RepositoryUpdateRequestFormData.as_form), # type: ignore[attr-defined]
) -> RepositoryUpdate:
try:
diff --git a/lib/tool_shed/webapp/api2/repository.py b/lib/tool_shed/webapp/api2/repository.py
index c02cdab559b..e4504b9c8d6 100644
--- a/lib/tool_shed/webapp/api2/repository.py
+++ b/lib/tool_shed/webapp/api2/repository.py
@@ -9,7 +9,6 @@ migrated here so the legacy WSGI controller can be deleted.
import logging
import mimetypes
import os
-from typing import Optional
from fastapi import Form
from starlette.requests import Request
@@ -176,7 +175,7 @@ class FastAPILegacyInstall:
def get_required_repo_info_dict(
self,
trans: SessionRequestContext = DependsOnTrans,
- encoded_str: Optional[str] = Form(default=None),
+ encoded_str: str | None = Form(default=None),
) -> dict:
return get_required_repo_info_dict_from_encoded(trans, encoded_str)
diff --git a/lib/tool_shed/webapp/api2/users.py b/lib/tool_shed/webapp/api2/users.py
index cbb20205b6d..842d008c2c6 100644
--- a/lib/tool_shed/webapp/api2/users.py
+++ b/lib/tool_shed/webapp/api2/users.py
@@ -1,8 +1,5 @@
import logging
import os
-from typing import (
- Optional,
-)
from fastapi import (
Body,
@@ -56,7 +53,7 @@ router = Router(tags=["users"])
log = logging.getLogger(__name__)
-TOOL_SHED_SENSITIVE_API_REQUEST_LIMIT: Optional[str] = os.environ.get("TOOL_SHED_SENSITIVE_API_REQUEST_LIMIT", None)
+TOOL_SHED_SENSITIVE_API_REQUEST_LIMIT: str | None = os.environ.get("TOOL_SHED_SENSITIVE_API_REQUEST_LIMIT", None)
SENSITIVE_API_REQUEST_LIMIT = TOOL_SHED_SENSITIVE_API_REQUEST_LIMIT or "10/minute"
@@ -92,7 +89,7 @@ class UiRegisterResponse(BaseModel):
email: str
activation_sent: bool = False
activation_error: bool = False
- contact_email: Optional[str] = None
+ contact_email: str | None = None
class UiChangePasswordRequest(BaseModel):
diff --git a/lib/tool_shed/webapp/app.py b/lib/tool_shed/webapp/app.py
index 33767b01009..020c819154a 100644
--- a/lib/tool_shed/webapp/app.py
+++ b/lib/tool_shed/webapp/app.py
@@ -1,7 +1,6 @@
import logging
import sys
import time
-from typing import Optional
from sqlalchemy.orm.scoping import scoped_session
@@ -116,4 +115,4 @@ class UniverseApplication(ToolShedApp, SentryClientMixin, HaltableContainer):
# Global instance of the universe app.
-app: Optional[ToolShedApp] = None
+app: ToolShedApp | None = None
diff --git a/lib/tool_shed/webapp/fast_app.py b/lib/tool_shed/webapp/fast_app.py
index 034c8b7bb5f..1f1785539e3 100644
--- a/lib/tool_shed/webapp/fast_app.py
+++ b/lib/tool_shed/webapp/fast_app.py
@@ -4,7 +4,6 @@ from pathlib import Path
from typing import (
Any,
cast,
- Optional,
)
from a2wsgi import WSGIMiddleware
@@ -60,7 +59,7 @@ api_tags_metadata = [
# pnpm dev
# Start tool shed with:
# TOOL_SHED_VITE_PORT=4040 ./run_tool_shed.sh
-TOOL_SHED_VITE_PORT: Optional[str] = os.environ.get("TOOL_SHED_VITE_PORT", None)
+TOOL_SHED_VITE_PORT: str | None = os.environ.get("TOOL_SHED_VITE_PORT", None)
TOOL_SHED_FRONTEND_TARGET: str = os.environ.get("TOOL_SHED_FRONTEND_TARGET") or "auto" # auto, src, or node
TOOL_SHED_USE_HMR: bool = TOOL_SHED_VITE_PORT is not None
WEBAPP_DIR = Path(__file__).parent.resolve()
diff --git a/lib/tool_shed/webapp/model/__init__.py b/lib/tool_shed/webapp/model/__init__.py
index 55e9b71e67e..7174dcc3c2d 100644
--- a/lib/tool_shed/webapp/model/__init__.py
+++ b/lib/tool_shed/webapp/model/__init__.py
@@ -10,7 +10,6 @@ from datetime import (
)
from typing import (
Any,
- Optional,
TYPE_CHECKING,
)
@@ -98,26 +97,26 @@ class APIKeys(Base):
__tablename__ = "api_keys"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- key: Mapped[Optional[str]] = mapped_column(TrimmedString(32), index=True, unique=True)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ key: Mapped[str | None] = mapped_column(TrimmedString(32), index=True, unique=True)
user = relationship("User", back_populates="api_keys")
- deleted: Mapped[Optional[bool]] = mapped_column(index=True, default=False, nullable=False)
+ deleted: Mapped[bool | None] = mapped_column(index=True, default=False, nullable=False)
class User(Base, Dictifiable):
__tablename__ = "galaxy_user"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
email: Mapped[str] = mapped_column(TrimmedString(255), nullable=False)
- username: Mapped[Optional[str]] = mapped_column(String(255), index=True)
+ username: Mapped[str | None] = mapped_column(String(255), index=True)
password: Mapped[str] = mapped_column(TrimmedString(40), nullable=False)
- external: Mapped[Optional[bool]] = mapped_column(Boolean, default=False)
- new_repo_alert: Mapped[Optional[bool]] = mapped_column(Boolean, default=False)
- deleted: Mapped[Optional[bool]] = mapped_column(Boolean, index=True, default=False)
- purged: Mapped[Optional[bool]] = mapped_column(Boolean, index=True, default=False)
+ external: Mapped[bool | None] = mapped_column(Boolean, default=False)
+ new_repo_alert: Mapped[bool | None] = mapped_column(Boolean, default=False)
+ deleted: Mapped[bool | None] = mapped_column(Boolean, index=True, default=False)
+ purged: Mapped[bool | None] = mapped_column(Boolean, index=True, default=False)
active_repositories = relationship(
"Repository",
primaryjoin=(lambda: (Repository.user_id == User.id) & (not_(Repository.deleted))),
@@ -139,9 +138,11 @@ class User(Base, Dictifiable):
"UserRoleAssociation",
viewonly=True,
primaryjoin=(
- lambda: (User.id == UserRoleAssociation.user_id)
- & (UserRoleAssociation.role_id == Role.id)
- & not_(Role.name == User.email)
+ lambda: (
+ (User.id == UserRoleAssociation.user_id)
+ & (UserRoleAssociation.role_id == Role.id)
+ & not_(Role.name == User.email)
+ )
),
)
@@ -203,8 +204,8 @@ class PasswordResetToken(Base):
__tablename__ = "password_reset_token"
token: Mapped[str] = mapped_column(String(32), primary_key=True, unique=True, index=True)
- expiration_time: Mapped[Optional[datetime]] = mapped_column(DateTime)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ expiration_time: Mapped[datetime | None] = mapped_column(DateTime)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
user = relationship("User", back_populates="reset_tokens")
def __init__(self, user, token=None):
@@ -221,10 +222,10 @@ class Group(Base, Dictifiable):
__tablename__ = "galaxy_group"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
- name: Mapped[Optional[str]] = mapped_column(String(255), index=True, unique=True)
- deleted: Mapped[Optional[bool]] = mapped_column(Boolean, index=True, default=False)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
+ name: Mapped[str | None] = mapped_column(String(255), index=True, unique=True)
+ deleted: Mapped[bool | None] = mapped_column(Boolean, index=True, default=False)
roles = relationship("GroupRoleAssociation", back_populates="group")
users = relationship("UserGroupAssociation", back_populates="group")
@@ -240,12 +241,12 @@ class Role(Base, Dictifiable):
__tablename__ = "role"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
- name: Mapped[Optional[str]] = mapped_column(String(255), index=True, unique=True)
- description: Mapped[Optional[str]] = mapped_column(TEXT)
- type: Mapped[Optional[str]] = mapped_column(String(40), index=True)
- deleted: Mapped[Optional[bool]] = mapped_column(Boolean, index=True, default=False)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
+ name: Mapped[str | None] = mapped_column(String(255), index=True, unique=True)
+ description: Mapped[str | None] = mapped_column(TEXT)
+ type: Mapped[str | None] = mapped_column(String(40), index=True)
+ deleted: Mapped[bool | None] = mapped_column(Boolean, index=True, default=False)
repositories = relationship("RepositoryRoleAssociation", back_populates="role")
groups = relationship("GroupRoleAssociation", back_populates="role")
users = relationship("UserRoleAssociation", back_populates="role")
@@ -275,10 +276,10 @@ class UserGroupAssociation(Base):
__tablename__ = "user_group_association"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- group_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_group.id"), index=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ group_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_group.id"), index=True)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
user = relationship("User", back_populates="groups")
group = relationship("Group", back_populates="users")
@@ -292,10 +293,10 @@ class UserRoleAssociation(Base):
__tablename__ = "user_role_association"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
user = relationship("User", back_populates="roles")
role = relationship("Role", back_populates="users")
@@ -310,10 +311,10 @@ class GroupRoleAssociation(Base):
__tablename__ = "group_role_association"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- group_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_group.id"), index=True)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
+ group_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_group.id"), index=True)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
group = relationship("Group", back_populates="roles")
role = relationship("Role", back_populates="groups")
@@ -326,10 +327,10 @@ class RepositoryRoleAssociation(Base):
__tablename__ = "repository_role_association"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- repository_id: Mapped[Optional[int]] = mapped_column(ForeignKey("repository.id"), index=True)
- role_id: Mapped[Optional[int]] = mapped_column(ForeignKey("role.id"), index=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
+ repository_id: Mapped[int | None] = mapped_column(ForeignKey("repository.id"), index=True)
+ role_id: Mapped[int | None] = mapped_column(ForeignKey("role.id"), index=True)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
repository = relationship("Repository", back_populates="roles")
role = relationship("Role", back_populates="repositories")
@@ -343,18 +344,18 @@ class GalaxySession(Base):
__tablename__ = "galaxy_session"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True, nullable=True)
- remote_host: Mapped[Optional[str]] = mapped_column(String(255))
- remote_addr: Mapped[Optional[str]] = mapped_column(String(255))
- referer: Mapped[Optional[str]] = mapped_column(TEXT)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True, nullable=True)
+ remote_host: Mapped[str | None] = mapped_column(String(255))
+ remote_addr: Mapped[str | None] = mapped_column(String(255))
+ referer: Mapped[str | None] = mapped_column(TEXT)
# unique 128 bit random number coerced to a string
- session_key: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True, unique=True)
- is_valid: Mapped[Optional[bool]] = mapped_column(Boolean, default=False)
+ session_key: Mapped[str | None] = mapped_column(TrimmedString(255), index=True, unique=True)
+ is_valid: Mapped[bool | None] = mapped_column(Boolean, default=False)
# saves a reference to the previous session so we have a way to chain them together
- prev_session_id: Mapped[Optional[int]] = mapped_column(Integer)
- last_action: Mapped[Optional[datetime]] = mapped_column(DateTime)
+ prev_session_id: Mapped[int | None] = mapped_column(Integer)
+ last_action: Mapped[datetime | None] = mapped_column(DateTime)
user = relationship("User", back_populates="galaxy_sessions")
def __init__(self, is_valid=False, **kwd):
@@ -367,20 +368,20 @@ class Repository(Base, Dictifiable):
__tablename__ = "repository"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
- name: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- type: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True)
- remote_repository_url: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- homepage_url: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
- description: Mapped[Optional[str]] = mapped_column(TEXT)
- long_description: Mapped[Optional[str]] = mapped_column(TEXT)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- private: Mapped[Optional[bool]] = mapped_column(Boolean, default=False)
- deleted: Mapped[Optional[bool]] = mapped_column(Boolean, index=True, default=False)
- email_alerts: Mapped[Optional[bytes]] = mapped_column(MutableJSONType, nullable=True)
- times_downloaded: Mapped[Optional[int]] = mapped_column(Integer)
- deprecated: Mapped[Optional[bool]] = mapped_column(Boolean, default=False)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
+ name: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ type: Mapped[str | None] = mapped_column(TrimmedString(255), index=True)
+ remote_repository_url: Mapped[str | None] = mapped_column(TrimmedString(255))
+ homepage_url: Mapped[str | None] = mapped_column(TrimmedString(255))
+ description: Mapped[str | None] = mapped_column(TEXT)
+ long_description: Mapped[str | None] = mapped_column(TEXT)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ private: Mapped[bool | None] = mapped_column(Boolean, default=False)
+ deleted: Mapped[bool | None] = mapped_column(Boolean, index=True, default=False)
+ email_alerts: Mapped[bytes | None] = mapped_column(MutableJSONType, nullable=True)
+ times_downloaded: Mapped[int | None] = mapped_column(Integer)
+ deprecated: Mapped[bool | None] = mapped_column(Boolean, default=False)
categories = relationship("RepositoryCategoryAssociation", back_populates="repository")
ratings = relationship(
"RepositoryRatingAssociation",
@@ -390,8 +391,9 @@ 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()),
+ primaryjoin=lambda: (
+ (Repository.id == RepositoryMetadata.repository_id) & (RepositoryMetadata.downloadable == true())
+ ),
viewonly=True,
order_by=lambda: desc(RepositoryMetadata.update_time),
)
@@ -624,12 +626,12 @@ class RepositoryRatingAssociation(Base, ItemRatingAssociation):
__tablename__ = "repository_rating_association"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
- repository_id: Mapped[Optional[int]] = mapped_column(ForeignKey("repository.id"), index=True)
- user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
- rating: Mapped[Optional[int]] = mapped_column(Integer, index=True)
- comment: Mapped[Optional[str]] = mapped_column(TEXT)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
+ repository_id: Mapped[int | None] = mapped_column(ForeignKey("repository.id"), index=True)
+ user_id: Mapped[int | None] = mapped_column(ForeignKey("galaxy_user.id"), index=True)
+ rating: Mapped[int | None] = mapped_column(Integer, index=True)
+ comment: Mapped[str | None] = mapped_column(TEXT)
repository = relationship("Repository", back_populates="ratings")
user = relationship("User")
@@ -641,11 +643,11 @@ class Category(Base, Dictifiable):
__tablename__ = "category"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- create_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now)
- update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, default=now, onupdate=now)
- name: Mapped[Optional[str]] = mapped_column(TrimmedString(255), index=True, unique=True)
- description: Mapped[Optional[str]] = mapped_column(TEXT)
- deleted: Mapped[Optional[bool]] = mapped_column(Boolean, index=True, default=False)
+ create_time: Mapped[datetime | None] = mapped_column(DateTime, default=now)
+ update_time: Mapped[datetime | None] = mapped_column(DateTime, default=now, onupdate=now)
+ name: Mapped[str | None] = mapped_column(TrimmedString(255), index=True, unique=True)
+ description: Mapped[str | None] = mapped_column(TEXT)
+ deleted: Mapped[bool | None] = mapped_column(Boolean, index=True, default=False)
repositories = relationship("RepositoryCategoryAssociation", back_populates="category")
dict_collection_visible_keys = ["id", "name", "description", "deleted"]
@@ -676,8 +678,8 @@ class RepositoryCategoryAssociation(Base):
__tablename__ = "repository_category_association"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- repository_id: Mapped[Optional[int]] = mapped_column(ForeignKey("repository.id"), index=True)
- category_id: Mapped[Optional[int]] = mapped_column(ForeignKey("category.id"), index=True)
+ repository_id: Mapped[int | None] = mapped_column(ForeignKey("repository.id"), index=True)
+ category_id: Mapped[int | None] = mapped_column(ForeignKey("category.id"), index=True)
category = relationship("Category", back_populates="repositories")
repository = relationship("Repository", back_populates="categories")
@@ -691,9 +693,9 @@ class Tag(Base):
__table_args__ = (UniqueConstraint("name"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True)
- type: Mapped[Optional[int]] = mapped_column(Integer)
- parent_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tag.id"))
- name: Mapped[Optional[str]] = mapped_column(TrimmedString(255))
+ type: Mapped[int | None] = mapped_column(Integer)
+ parent_id: Mapped[int | None] = mapped_column(ForeignKey("tag.id"))
+ name: Mapped[str | None] = mapped_column(TrimmedString(255))
children = relationship("Tag", back_populates="parent")
parent = relationship("Tag", back_populates="children", remote_side=[id])
@@ -708,22 +710,22 @@ class Tag(Base):
class RepositoryMetadata(Dictifiable):
# Annotations only — runtime attributes are installed by
# mapper_registry.map_imperatively below.
- id: Mapped[Optional[int]]
- create_time: Mapped[Optional[datetime]]
- update_time: Mapped[Optional[datetime]]
- repository_id: Mapped[Optional[int]]
- changeset_revision: Mapped[Optional[str]]
- numeric_revision: Mapped[Optional[int]]
+ id: Mapped[int | None]
+ create_time: Mapped[datetime | None]
+ update_time: Mapped[datetime | None]
+ repository_id: Mapped[int | None]
+ changeset_revision: Mapped[str | None]
+ numeric_revision: Mapped[int | None]
metadata: Mapped[Any]
tool_versions: Mapped[Any]
- malicious: Mapped[Optional[bool]]
- downloadable: Mapped[Optional[bool]]
- missing_test_components: Mapped[Optional[bool]]
- has_repository_dependencies: Mapped[Optional[bool]]
- includes_datatypes: Mapped[Optional[bool]]
- includes_tools: Mapped[Optional[bool]]
- includes_tool_dependencies: Mapped[Optional[bool]]
- includes_workflows: Mapped[Optional[bool]]
+ malicious: Mapped[bool | None]
+ downloadable: Mapped[bool | None]
+ missing_test_components: Mapped[bool | None]
+ has_repository_dependencies: Mapped[bool | None]
+ includes_datatypes: Mapped[bool | None]
+ includes_tools: Mapped[bool | None]
+ includes_tool_dependencies: Mapped[bool | None]
+ includes_workflows: Mapped[bool | None]
repository: Mapped["Repository"]
table = Table(
diff --git a/lib/tool_shed/webapp/model/mapping.py b/lib/tool_shed/webapp/model/mapping.py
index 75bc6b65f72..661c33a9f9e 100644
--- a/lib/tool_shed/webapp/model/mapping.py
+++ b/lib/tool_shed/webapp/model/mapping.py
@@ -6,7 +6,6 @@ are encapsulated here.
import logging
from typing import (
Any,
- Optional,
TYPE_CHECKING,
)
@@ -32,9 +31,7 @@ class ToolShedModelMapping(SharedModelMapping):
create_tables: bool
-def init(
- url: str, engine_options: Optional[dict[str, Any]] = None, create_tables: bool = False
-) -> ToolShedModelMapping:
+def init(url: str, engine_options: dict[str, Any] | None = None, create_tables: bool = False) -> ToolShedModelMapping:
"""Connect mappings to the database"""
engine_options = engine_options or {}
# Create the database engine
diff --git a/lib/tool_shed/webapp/model/migrations/__init__.py b/lib/tool_shed/webapp/model/migrations/__init__.py
index ea50ec2350a..5fdd8a9ab97 100644
--- a/lib/tool_shed/webapp/model/migrations/__init__.py
+++ b/lib/tool_shed/webapp/model/migrations/__init__.py
@@ -3,7 +3,6 @@ import os
from collections.abc import Iterable
from typing import (
cast,
- Optional,
)
import alembic
@@ -82,13 +81,13 @@ class AlembicManager(BaseAlembicManager):
log.info(f"Revision {db_head} does not exist in the script directory.")
return False
- def get_db_head(self) -> Optional[str]:
+ def get_db_head(self) -> str | None:
return self._get_head_revision(cast(Iterable[str], self.db_heads))
- def get_script_head(self) -> Optional[str]:
+ def get_script_head(self) -> str | None:
return self.script_directory.get_current_head()
- def _get_head_revision(self, heads: Iterable[str]) -> Optional[str]:
+ def _get_head_revision(self, heads: Iterable[str]) -> str | None:
for head in heads:
if self._get_revision(head):
return head
@@ -100,8 +99,8 @@ class DatabaseStateVerifier:
self.engine = engine
self.metadata = Base.metadata
# These values may or may not be required, so do a lazy load.
- self._db_state: Optional[DatabaseStateCache] = None
- self._alembic_manager: Optional[AlembicManager] = None
+ self._db_state: DatabaseStateCache | None = None
+ self._alembic_manager: AlembicManager | None = None
@property
def db_state(self) -> DatabaseStateCache:
diff --git a/lib/tool_shed/webapp/model/migrations/dbscript.py b/lib/tool_shed/webapp/model/migrations/dbscript.py
index 11c23efa173..79fbfe92261 100644
--- a/lib/tool_shed/webapp/model/migrations/dbscript.py
+++ b/lib/tool_shed/webapp/model/migrations/dbscript.py
@@ -2,7 +2,6 @@ import logging
import os
import sys
from argparse import Namespace
-from typing import Optional
from galaxy.model.migrations.base import (
BaseCommand,
@@ -52,7 +51,7 @@ class Command(BaseCommand):
class DbScript(BaseDbScript):
- def _set_dburl(self, config_file: Optional[str] = None) -> None:
+ def _set_dburl(self, config_file: str | None = None) -> None:
self.url = get_dburl_from_file(os.getcwd(), config_file)
self.alembic_config.set_main_option("sqlalchemy.url", self.url)
diff --git a/lib/tool_shed/webapp/model/migrations/scripts.py b/lib/tool_shed/webapp/model/migrations/scripts.py
index c9d5a0d00ff..30bcb3d278b 100644
--- a/lib/tool_shed/webapp/model/migrations/scripts.py
+++ b/lib/tool_shed/webapp/model/migrations/scripts.py
@@ -1,7 +1,4 @@
import os
-from typing import (
- Optional,
-)
from galaxy.model.migrations.base import pop_arg_from_args
from galaxy.util.properties import (
@@ -22,7 +19,7 @@ def get_dburl(argv: list[str], cwd: str) -> str:
return get_dburl_from_file(cwd, config_file)
-def get_dburl_from_file(cwd: str, config_file: Optional[str] = None) -> str:
+def get_dburl_from_file(cwd: str, config_file: str | None = None) -> str:
if config_file is None:
cwds = [cwd, os.path.join(cwd, CONFIG_DIR_NAME)]
config_file = find_config_file(DEFAULT_CONFIG_NAMES, dirs=cwds)
diff --git a/lib/tool_shed_client/schema/__init__.py b/lib/tool_shed_client/schema/__init__.py
index eea9b8a1010..cb9ff5a1030 100644
--- a/lib/tool_shed_client/schema/__init__.py
+++ b/lib/tool_shed_client/schema/__init__.py
@@ -2,7 +2,6 @@ from typing import (
Any,
Literal,
Optional,
- Union,
)
from pydantic import (
@@ -24,8 +23,8 @@ class Repository(BaseModel):
name: str
owner: str
type: str # TODO: enum
- remote_repository_url: Optional[str] = None
- homepage_url: Optional[str] = None
+ remote_repository_url: str | None = None
+ homepage_url: str | None = None
description: str
user_id: str
private: bool
@@ -37,7 +36,7 @@ class Repository(BaseModel):
class DetailedRepository(Repository):
- long_description: Optional[str]
+ long_description: str | None
class RepositoryPermissions(BaseModel):
@@ -75,7 +74,7 @@ class Category(BaseModel):
class CreateCategoryRequest(BaseModel):
name: str
- description: Optional[str] = None
+ description: str | None = None
class ValidRepostiroyUpdateMessage(BaseModel):
@@ -105,15 +104,15 @@ RepositoryType = Literal[
class CreateRepositoryRequest(BaseModel):
name: str
synopsis: str
- description: Optional[str] = None
- remote_repository_url: Optional[str] = None
- homepage_url: Optional[str] = None
+ description: str | None = None
+ remote_repository_url: str | None = None
+ homepage_url: str | None = None
type_: RepositoryType = Field(
"unrestricted",
alias="type",
title="Type",
)
- category_ids: Optional[Union[list[str], str]] = Field(
+ category_ids: list[str] | str | None = Field(
...,
alias="category_ids[]",
title="Category IDs",
@@ -122,17 +121,17 @@ class CreateRepositoryRequest(BaseModel):
class UpdateRepositoryRequest(BaseModel):
- name: Optional[str] = None
- synopsis: Optional[str] = None
- type_: Optional[RepositoryType] = Field(
+ name: str | None = None
+ synopsis: str | None = None
+ type_: RepositoryType | None = Field(
None,
alias="type",
title="Type",
)
- description: Optional[str] = None
- remote_repository_url: Optional[str] = None
- homepage_url: Optional[str] = None
- category_ids: Optional[list[str]] = Field(
+ description: str | None = None
+ remote_repository_url: str | None = None
+ homepage_url: str | None = None
+ category_ids: list[str] | None = Field(
None,
alias="category_ids",
title="Category IDs",
@@ -141,11 +140,11 @@ class UpdateRepositoryRequest(BaseModel):
class RepositoryUpdateRequest(BaseModel):
- commit_message: Optional[str] = None
+ commit_message: str | None = None
class RepositoryUpdate(RootModel):
- root: Union[ValidRepostiroyUpdateMessage, FailedRepositoryUpdateMessage]
+ root: ValidRepostiroyUpdateMessage | FailedRepositoryUpdateMessage
@property
def is_ok(self):
@@ -177,7 +176,7 @@ class RepositoryRevisionMetadata(BaseModel):
id: str
repository: Repository
repository_dependencies: list["RepositoryDependency"]
- tools: Optional[list["RepositoryTool"]] = None
+ tools: list["RepositoryTool"] | None = None
invalid_tools: list[InvalidTool]
repository_id: str
numeric_revision: int
@@ -190,9 +189,9 @@ class RepositoryRevisionMetadata(BaseModel):
includes_tools_for_display_in_tool_panel: bool
create_time: str
# Deprecate these...
- includes_tool_dependencies: Optional[bool] = None
- includes_datatypes: Optional[bool] = None
- includes_workflows: Optional[bool] = None
+ includes_tool_dependencies: bool | None = None
+ includes_datatypes: bool | None = None
+ includes_workflows: bool | None = None
class RepositoryDependency(RepositoryRevisionMetadata):
@@ -228,13 +227,13 @@ class RepositoryRevisionMetadataPreview(BaseModel):
changesets that haven't been indexed yet.
"""
- id: Optional[str] = None
+ id: str | None = None
repository: Repository
repository_dependencies: list["RepositoryDependency"]
- tools: Optional[list["RepositoryTool"]] = None
+ tools: list["RepositoryTool"] | None = None
invalid_tools: list[InvalidTool] = []
- repository_id: Optional[str] = None
- numeric_revision: Optional[int] = None
+ repository_id: str | None = None
+ numeric_revision: int | None = None
changeset_revision: str
malicious: bool
downloadable: bool
@@ -242,10 +241,10 @@ class RepositoryRevisionMetadataPreview(BaseModel):
has_repository_dependencies: bool
includes_tools: bool
includes_tools_for_display_in_tool_panel: bool
- create_time: Optional[str] = None
- includes_tool_dependencies: Optional[bool] = None
- includes_datatypes: Optional[bool] = None
- includes_workflows: Optional[bool] = None
+ create_time: str | None = None
+ includes_tool_dependencies: bool | None = None
+ includes_datatypes: bool | None = None
+ includes_workflows: bool | None = None
class RepositoryMetadataPreview(RootModel):
@@ -265,12 +264,12 @@ class ChangesetMetadataStatus(BaseModel):
changeset_revision: str
numeric_revision: int
- comparison_result: Optional[str] = None # "initial", "equal", "subset", "not_equal_and_not_subset", "no_metadata"
- record_operation: Optional[Literal["created", "updated"]] = None
+ comparison_result: str | None = None # "initial", "equal", "subset", "not_equal_and_not_subset", "no_metadata"
+ record_operation: Literal["created", "updated"] | None = None
has_tools: bool = False
has_repository_dependencies: bool = False
has_tool_dependencies: bool = False
- error: Optional[str] = None
+ error: str | None = None
class ResetMetadataOnRepositoryResponse(BaseModel):
@@ -279,7 +278,7 @@ class ResetMetadataOnRepositoryResponse(BaseModel):
start_time: str
stop_time: str
dry_run: bool = False
- changeset_details: Optional[list[ChangesetMetadataStatus]] = None
+ changeset_details: list[ChangesetMetadataStatus] | None = None
# Full metadata snapshots for diffing (only when verbose=True)
# Uses Preview types since dry-run objects may lack IDs
repository_metadata_before: Optional["RepositoryMetadataPreview"] = None
@@ -295,7 +294,7 @@ to True will restrict resetting metadata to only repositories that are writable
in addition to those repositories of type tool_dependency_definition. This param is ignored
if the current user is not an admin user, in which case this same restriction is automatic.""",
)
- encoded_ids_to_skip: Optional[list[str]] = Field(
+ encoded_ids_to_skip: list[str] | None = Field(
None, description="a list of encoded repository ids for repositories that should not be processed"
)
@@ -308,8 +307,8 @@ class ResetMetadataOnRepositoriesResponse(BaseModel):
class ToolSearchRequest(BaseModel):
q: str
- page: Optional[int] = None
- page_size: Optional[int] = None
+ page: int | None = None
+ page_size: int | None = None
class ToolSearchHitTool(BaseModel):
@@ -334,8 +333,8 @@ class ToolSearchResults(BaseModel):
hostname: str
hits: list[ToolSearchHit]
- def find_search_hit(self, repository: Repository) -> Optional[ToolSearchHit]:
- matching_hit: Optional[ToolSearchHit] = None
+ def find_search_hit(self, repository: Repository) -> ToolSearchHit | None:
+ matching_hit: ToolSearchHit | None = None
for hit in self.hits:
owner_matches = hit.tool.repo_owner_username == repository.owner
@@ -351,13 +350,13 @@ IndexSortByType = Literal["name", "create_time"]
class RepositoryIndexRequest(BaseModel):
- filter: Optional[str] = None
- owner: Optional[str] = None
- name: Optional[str] = None
+ filter: str | None = None
+ owner: str | None = None
+ name: str | None = None
deleted: str = "false"
- category_id: Optional[str] = None
- sort_by: Optional[IndexSortByType] = "name"
- sort_desc: Optional[bool] = False
+ category_id: str | None = None
+ sort_by: IndexSortByType | None = "name"
+ sort_desc: bool | None = False
class RepositoryPaginatedIndexRequest(RepositoryIndexRequest):
@@ -379,8 +378,8 @@ class RepositoryIndexResponse(RootModel):
class RepositorySearchRequest(BaseModel):
q: str
- page: Optional[int] = None
- page_size: Optional[int] = None
+ page: int | None = None
+ page_size: int | None = None
class RepositorySearchResult(BaseModel):
@@ -388,10 +387,10 @@ class RepositorySearchResult(BaseModel):
name: str
repo_owner_username: str
description: str
- long_description: Optional[str] = None
- remote_repository_url: Optional[str] = None
- homepage_url: Optional[str] = None
- last_update: Optional[str] = None
+ long_description: str | None = None
+ remote_repository_url: str | None = None
+ homepage_url: str | None = None
+ last_update: str | None = None
full_last_updated: str
repo_lineage: str
approved: bool
@@ -438,7 +437,7 @@ class ValidToolDict(TypedDict):
tool_config: str
tool_type: str
version: str
- version_string_cmd: Optional[str]
+ version_string_cmd: str | None
class RepositoryMetadataInstallInfoDict(TypedDict):
@@ -478,9 +477,7 @@ class EmptyDict(TypedDict):
pass
-LegacyInstallInfoTuple = tuple[
- Optional[dict], Union[RepositoryMetadataInstallInfoDict, EmptyDict], Union[ExtraRepoInfo, EmptyDict]
-]
+LegacyInstallInfoTuple = tuple[dict | None, RepositoryMetadataInstallInfoDict | EmptyDict, ExtraRepoInfo | EmptyDict]
class RepositoryExtraInstallInfo(BaseModel):
@@ -490,7 +487,7 @@ class RepositoryExtraInstallInfo(BaseModel):
changeset_revision: str
ctx_rev: str
repository_owner: str
- repository_dependencies: Optional[dict] = None
+ repository_dependencies: dict | None = None
# tool dependencies not longer work so don't transmit them in v2?
# tool_dependencies: Optional[Dict]
@@ -521,7 +518,7 @@ class ValidTool(BaseModel):
tool_config: str
tool_type: str
version: str
- version_string_cmd: Optional[str] = None
+ version_string_cmd: str | None = None
@staticmethod
def from_legacy_dict(as_dict: ValidToolDict) -> "ValidTool":
@@ -566,13 +563,13 @@ class RepositoryMetadataInstallInfo(BaseModel):
class InstallInfo(BaseModel):
- metadata_info: Optional[RepositoryMetadataInstallInfo] = None
- repo_info: Optional[RepositoryExtraInstallInfo] = None
+ metadata_info: RepositoryMetadataInstallInfo | None = None
+ repo_info: RepositoryExtraInstallInfo | None = None
def from_legacy_install_info(legacy_install_info: LegacyInstallInfoTuple) -> InstallInfo:
- repo_metadata_install_info: Union[RepositoryMetadataInstallInfoDict, EmptyDict]
- extra_info: Union[ExtraRepoInfo, EmptyDict]
+ repo_metadata_install_info: RepositoryMetadataInstallInfoDict | EmptyDict
+ extra_info: ExtraRepoInfo | EmptyDict
_, repo_metadata_install_info, extra_info = legacy_install_info
if repo_metadata_install_info:
metadata_info = RepositoryMetadataInstallInfo.from_legacy_dict(repo_metadata_install_info)
@@ -600,4 +597,4 @@ class Version(BaseModel):
class ShedParsedTool(ParsedTool):
- repository_revision: Optional[RepositoryRevisionMetadata] = None
+ repository_revision: RepositoryRevisionMetadata | None = None
diff --git a/packages/job_metrics/pyproject.toml b/packages/job_metrics/pyproject.toml
index 68e8e32c338..25d936c5e87 100644
--- a/packages/job_metrics/pyproject.toml
+++ b/packages/job_metrics/pyproject.toml
@@ -7,14 +7,13 @@ dynamic = ["readme"]
name = "galaxy-job-metrics"
version = "26.1.dev0"
description = "Galaxy job metrics"
-requires-python = ">=3.8"
+requires-python = ">=3.10"
license = {"text" = "MIT"}
authors = [
{name = "Galaxy Project and Community", email = "galaxy-committers@lists.galaxyproject.org"},
]
dependencies = [
"galaxy-util",
- "backports.zoneinfo;python_version<'3.9'",
]
classifiers = [
"Development Status :: 5 - Production/Stable",
@@ -23,8 +22,6 @@ classifiers = [
"Natural Language :: English",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
diff --git a/packages/objectstore/pyproject.toml b/packages/objectstore/pyproject.toml
index 6054e5a93f9..68fb1eba90a 100644
--- a/packages/objectstore/pyproject.toml
+++ b/packages/objectstore/pyproject.toml
@@ -7,7 +7,7 @@ dynamic = ["readme"]
name = "galaxy-objectstore"
version = "26.1.dev0"
description = "Galaxy objectstore framework and plugins"
-requires-python = ">=3.8"
+requires-python = ">=3.10"
license = {"text" = "MIT"}
authors = [
{name = "Galaxy Project and Community", email = "galaxy-committers@lists.galaxyproject.org"},
@@ -24,8 +24,6 @@ classifiers = [
"Natural Language :: English",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
diff --git a/packages/tool_util/pyproject.toml b/packages/tool_util/pyproject.toml
index 624391832e9..884f7a84691 100644
--- a/packages/tool_util/pyproject.toml
+++ b/packages/tool_util/pyproject.toml
@@ -7,7 +7,7 @@ dynamic = ["readme"]
name = "galaxy-tool-util"
version = "26.1.dev0"
description = "Galaxy tool and tool dependency utilities"
-requires-python = ">=3.8"
+requires-python = ">=3.10"
license = {"text" = "MIT"}
authors = [
{name = "Galaxy Project and Community", email = "galaxy-committers@lists.galaxyproject.org"},
@@ -33,8 +33,6 @@ classifiers = [
"Natural Language :: English",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
diff --git a/packages/tool_util_models/pyproject.toml b/packages/tool_util_models/pyproject.toml
index 13dc3b899e4..18a7cde1f21 100644
--- a/packages/tool_util_models/pyproject.toml
+++ b/packages/tool_util_models/pyproject.toml
@@ -7,7 +7,7 @@ dynamic = ["readme"]
name = "galaxy-tool-util-models"
version = "26.1.dev0"
description = "Pydantic models for Galaxy tools"
-requires-python = ">=3.8"
+requires-python = ">=3.10"
license = {"text" = "MIT"}
authors = [
{name = "Galaxy Project and Community", email = "galaxy-committers@lists.galaxyproject.org"},
@@ -24,8 +24,6 @@ classifiers = [
"Natural Language :: English",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
diff --git a/packages/util/pyproject.toml b/packages/util/pyproject.toml
index 5cc1aa40486..205652fc499 100644
--- a/packages/util/pyproject.toml
+++ b/packages/util/pyproject.toml
@@ -7,7 +7,7 @@ dynamic = ["readme"]
name = "galaxy-util"
version = "26.1.dev0"
description = "Galaxy generic utilities"
-requires-python = ">=3.8"
+requires-python = ">=3.10"
license = {"text" = "MIT"}
authors = [
{name = "Galaxy Project and Community", email = "galaxy-committers@lists.galaxyproject.org"},
@@ -31,8 +31,6 @@ classifiers = [
"Natural Language :: English",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
diff --git a/packages/web_client/src/galaxy/web_client/install.py b/packages/web_client/src/galaxy/web_client/install.py
index 09df111bc51..e797fc42b0e 100644
--- a/packages/web_client/src/galaxy/web_client/install.py
+++ b/packages/web_client/src/galaxy/web_client/install.py
@@ -32,13 +32,15 @@ try:
import galaxy.webapps.base
STATIC = os.path.join(os.path.dirname(galaxy.webapps.base.__file__), "static")
- TARGETS.update({
- "style": os.path.join(STATIC, "style"),
- "favicon.ico": os.path.join(STATIC, "favicon.ico"),
- "favicon.svg": os.path.join(STATIC, "favicon.svg"),
- "robots.txt": os.path.join(STATIC, "robots.txt"),
- "welcome.sample.html": os.path.join(STATIC, "welcome.sample.html"),
- })
+ TARGETS.update(
+ {
+ "style": os.path.join(STATIC, "style"),
+ "favicon.ico": os.path.join(STATIC, "favicon.ico"),
+ "favicon.svg": os.path.join(STATIC, "favicon.svg"),
+ "robots.txt": os.path.join(STATIC, "robots.txt"),
+ "welcome.sample.html": os.path.join(STATIC, "welcome.sample.html"),
+ }
+ )
except ImportError:
# Consider this a soft fail, this package depends on nothing but is probably installed with galaxy-web-apps
pass
diff --git a/pyproject.toml b/pyproject.toml
index 2676ff8ad33..459d04c0669 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -223,8 +223,7 @@ select = ["E", "F", "B", "C4", "G", "ISC", "NPY", "UP"]
# E402 module level import not at top of file # TODO, we would like to improve this.
# E501 is line length (delegated to black)
# G* are TODOs
-# UP007, UP045: Python >=3.10 type annotation improvements, to be revisited later
-ignore = ["B008", "B9", "E402", "E501", "G001", "G002", "G004", "UP007", "UP045"]
+ignore = ["B008", "B9", "E402", "E501", "G001", "G002", "G004"]
[tool.ruff.lint.flake8-comprehensions]
allow-dict-calls-with-keyword-arguments = true
@@ -252,19 +251,6 @@ keep-runtime-typing = true
"lib/galaxy/schema/drs/*" = ["UP"]
"lib/tool_shed_client/schema/trs.py" = ["UP"]
"lib/tool_shed_client/schema/trs_service_info.py" = ["UP"]
-# Don't check some pyupgrade rules on packages for Pulsar, which need to stay compatible with Python 3.8
-"lib/galaxy/exceptions/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"lib/galaxy/job_metrics/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"lib/galaxy/objectstore/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"lib/galaxy/tool_util/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"lib/galaxy/tool_util_models/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"lib/galaxy/util/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"scripts/check_python.py" = ["UP006", "UP007", "UP010", "UP032", "UP033", "UP035", "UP036", "UP045"]
-"test/unit/job_metrics/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"test/unit/objectstore/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"test/unit/tool_util/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"test/unit/tool_util_models/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
-"test/unit/util/*" = ["UP006", "UP007", "UP033", "UP035", "UP036", "UP045"]
[tool.uv]
constraint-dependencies = [
diff --git a/scripts/bootstrap_test_shed.py b/scripts/bootstrap_test_shed.py
index 3e7f387b44a..0538c79d133 100644
--- a/scripts/bootstrap_test_shed.py
+++ b/scripts/bootstrap_test_shed.py
@@ -12,7 +12,6 @@ import sys
import tempfile
from typing import (
Any,
- Optional,
)
sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, "lib")))
@@ -104,8 +103,8 @@ class RemoteToolShedPopulator(ToolShedPopulator):
for tests.
"""
- _categories_by_name: Optional[dict[str, Category]] = None
- _users_by_username: Optional[dict[str, dict[str, Any]]] = None
+ _categories_by_name: dict[str, Category] | None = None
+ _users_by_username: dict[str, dict[str, Any]] | None = None
_populators_by_username: dict[str, "RemoteToolShedPopulator"] = {}
def __init__(self, admin_interactor: ShedApiInteractor, user_interactor: ShedApiInteractor):
diff --git a/scripts/check_and_update_purged_on_duplicated_uuid.py b/scripts/check_and_update_purged_on_duplicated_uuid.py
index 5fbc6bc163b..b84bbe7101e 100644
--- a/scripts/check_and_update_purged_on_duplicated_uuid.py
+++ b/scripts/check_and_update_purged_on_duplicated_uuid.py
@@ -28,7 +28,6 @@ from galaxy.model.orm.scripts import get_config
from galaxy.objectstore import ObjectStore
if __name__ == "__main__":
-
from galaxy.celery import tasks # noqa: F401
config = get_config(sys.argv)
diff --git a/scripts/check_python.py b/scripts/check_python.py
index 79f4d2d7241..d83df5ca175 100644
--- a/scripts/check_python.py
+++ b/scripts/check_python.py
@@ -3,8 +3,6 @@ If the current installed Python version is not supported, prints an error
message to stderr and returns 1
"""
-from __future__ import print_function
-
import sys
MIN_VERSION_TUPLE = (3, 10)
@@ -17,15 +15,12 @@ def check_python():
else:
version_string = ".".join(str(_) for _ in sys.version_info[:3])
min_version_string = ".".join(str(_) for _ in MIN_VERSION_TUPLE)
- msg = """ERROR: Your Python version is: {}
-Galaxy is currently supported on Python >={} .
+ msg = f"""ERROR: Your Python version is: {version_string}
+Galaxy is currently supported on Python >={min_version_string} .
To run Galaxy, please install a supported Python version.
If a supported version is already installed but is not your default,
https://docs.galaxyproject.org/en/latest/admin/python.html contains instructions
-on how to force Galaxy to use a different version.""".format(
- version_string,
- min_version_string,
- )
+on how to force Galaxy to use a different version."""
print(msg, file=sys.stderr)
raise Exception(msg)
diff --git a/scripts/cleanup_datasets/admin_cleanup_datasets.py b/scripts/cleanup_datasets/admin_cleanup_datasets.py
index e464c6680a9..0be3ecf3b38 100755
--- a/scripts/cleanup_datasets/admin_cleanup_datasets.py
+++ b/scripts/cleanup_datasets/admin_cleanup_datasets.py
@@ -296,8 +296,7 @@ def _get_tool_id_for_hda(app, hda_id):
job_query = select(Job.tool_id).join(JTODA).where(JTODA.dataset_id == hda_id)
- tool_id = session.execute(job_query).scalars().first()
- if tool_id is not None:
+ if (tool_id := session.execute(job_query).scalars().first()) is not None:
return tool_id
hda = session.get(HistoryDatasetAssociation, hda_id)
diff --git a/scripts/extract_tool_sections_from_api.py b/scripts/extract_tool_sections_from_api.py
index 61668cd26da..0e375c95c23 100644
--- a/scripts/extract_tool_sections_from_api.py
+++ b/scripts/extract_tool_sections_from_api.py
@@ -16,7 +16,6 @@ import urllib.request
from pathlib import Path
from typing import (
Any,
- Optional,
)
import yaml
@@ -82,7 +81,7 @@ def represent_quoted_string(dumper: yaml.Dumper, data: str) -> yaml.ScalarNode:
QuotingDumper.add_representer(QuotedString, represent_quoted_string)
-def fetch_tools(api_url: Optional[str] = None, timeout: float = DEFAULT_TIMEOUT_SECONDS) -> list[dict[str, Any]]:
+def fetch_tools(api_url: str | None = None, timeout: float = DEFAULT_TIMEOUT_SECONDS) -> list[dict[str, Any]]:
"""Fetch tools from a Galaxy `/api/tools` endpoint.
Raises ``RuntimeError`` on transport / HTTP / decoding failures so the caller
@@ -274,7 +273,7 @@ def _build_arg_parser() -> argparse.ArgumentParser:
return parser
-def main(argv: Optional[list[str]] = None) -> int:
+def main(argv: list[str] | None = None) -> int:
args = _build_arg_parser().parse_args(argv)
global API_URL, OUTPUT_FILE
diff --git a/scripts/fix_dm_versions.py b/scripts/fix_dm_versions.py
index bdd2d539182..ca3ec92d7b4 100755
--- a/scripts/fix_dm_versions.py
+++ b/scripts/fix_dm_versions.py
@@ -62,7 +62,7 @@ for guid in guid_mapping:
tool_version = dm.find("./tool/version")
tool_version = tool_version.text
- new_guid = f"{guid[:guid.rfind('/')]}/{tool_version}"
+ new_guid = f"{guid[: guid.rfind('/')]}/{tool_version}"
dm.attrib["guid"] = new_guid
print(f"changing guid: {guid} -> {new_guid}")
if "version" in dm.attrib:
diff --git a/scripts/mypy_config_utils.py b/scripts/mypy_config_utils.py
index 6d475772ac7..c17b767af0c 100644
--- a/scripts/mypy_config_utils.py
+++ b/scripts/mypy_config_utils.py
@@ -1,7 +1,6 @@
import configparser
import os
from dataclasses import dataclass
-from typing import Optional
@dataclass
@@ -29,7 +28,7 @@ def main():
print(f"Warning section {entry.section_name} does not refer to existant files")
-def to_python_path(package_name: str) -> Optional[str]:
+def to_python_path(package_name: str) -> str | None:
path = os.path.join("lib", package_name.replace(".", "/"))
if os.path.exists(path + ".py"):
path = f"{path}.py"
diff --git a/scripts/release-diff.py b/scripts/release-diff.py
index 1c44e69a7af..d2fa8fcd2f8 100644
--- a/scripts/release-diff.py
+++ b/scripts/release-diff.py
@@ -105,7 +105,9 @@ def report_diff(added, changed, removed, new_files):
"Changed",
"The following configuration options have been changed",
changed,
- lambda x: f"- {x[0]} has changed from\n\n ::\n\n{_indent(x[1])}\n\n to\n\n ::\n\n{_indent(x[2])}\n\n",
+ lambda x: (
+ f"- {x[0]} has changed from\n\n ::\n\n{_indent(x[1])}\n\n to\n\n ::\n\n{_indent(x[2])}\n\n"
+ ),
)
if removed:
diff --git a/test/evals/datasets/bioinformatics_workflows.py b/test/evals/datasets/bioinformatics_workflows.py
index 2f9c209028a..fd68761ce1d 100644
--- a/test/evals/datasets/bioinformatics_workflows.py
+++ b/test/evals/datasets/bioinformatics_workflows.py
@@ -21,7 +21,6 @@ trans can't satisfy -- those cases fail loudly rather than silently.
from typing import (
Any,
- Optional,
)
from pydantic_ai.models import Model
@@ -173,8 +172,8 @@ Return a number; no commentary.
def bioinformatics_workflows_dataset(
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
) -> Dataset[str, str, dict[str, Any]]:
"""Build the bioinformatics_workflows Dataset.
diff --git a/test/evals/datasets/capabilities.py b/test/evals/datasets/capabilities.py
index 3fb4fbebe74..aa1a84f7ed9 100644
--- a/test/evals/datasets/capabilities.py
+++ b/test/evals/datasets/capabilities.py
@@ -17,7 +17,6 @@ EVALS_JUDGE_MODEL) so a model isn't grading its own output.
from typing import (
Any,
- Optional,
)
from pydantic_ai.models import Model
@@ -96,8 +95,8 @@ Return a number; no commentary.
def capabilities_dataset(
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
) -> Dataset[str, str, dict[str, Any]]:
"""Build the capabilities Dataset.
diff --git a/test/evals/datasets/custom_tool.py b/test/evals/datasets/custom_tool.py
index 99d8e39a237..cf13e39d242 100644
--- a/test/evals/datasets/custom_tool.py
+++ b/test/evals/datasets/custom_tool.py
@@ -23,7 +23,6 @@ check belongs in the live integration eval.
from typing import (
Any,
- Optional,
)
from pydantic_ai.models import Model
@@ -135,8 +134,8 @@ Return a number; no commentary.
def custom_tool_dataset(
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
) -> Dataset[str, dict, dict[str, Any]]:
"""Build the custom_tool Dataset.
diff --git a/test/evals/datasets/error_analysis.py b/test/evals/datasets/error_analysis.py
index 61c3db8f423..49e437aa13f 100644
--- a/test/evals/datasets/error_analysis.py
+++ b/test/evals/datasets/error_analysis.py
@@ -11,7 +11,6 @@ in prose form). Scored two ways:
from typing import (
Any,
- Optional,
)
from pydantic_ai.models import Model
@@ -95,8 +94,8 @@ Return a number; no commentary.
def error_analysis_dataset(
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
) -> Dataset[str, str, dict[str, Any]]:
"""Build the error_analysis Dataset.
diff --git a/test/evals/datasets/orchestrator_planning.py b/test/evals/datasets/orchestrator_planning.py
index da1f6f4700b..9ea716fba88 100644
--- a/test/evals/datasets/orchestrator_planning.py
+++ b/test/evals/datasets/orchestrator_planning.py
@@ -19,7 +19,6 @@ use) is captured before sub-execution and is what we score here.
from typing import (
Any,
- Optional,
)
from pydantic_evals import (
@@ -72,7 +71,7 @@ ORCHESTRATOR_CASES = [
def orchestrator_planning_dataset(
- only: Optional[list[str]] = None,
+ only: list[str] | None = None,
) -> Dataset[str, dict[str, Any], dict[str, Any]]:
cases = [c for c in ORCHESTRATOR_CASES if not only or c.name in only]
return Dataset(name="orchestrator_planning", cases=cases)
diff --git a/test/evals/datasets/router_tool_use.py b/test/evals/datasets/router_tool_use.py
index b9264f76c53..71ebd4e3739 100644
--- a/test/evals/datasets/router_tool_use.py
+++ b/test/evals/datasets/router_tool_use.py
@@ -23,7 +23,6 @@ the routing dataset.
from typing import (
Any,
- Optional,
)
from pydantic_evals import (
@@ -100,7 +99,7 @@ _PROTO_CASES: list[dict[str, Any]] = [
def router_tool_use_dataset(
- only: Optional[list[str]] = None,
+ only: list[str] | None = None,
) -> Dataset[str, Any, dict[str, Any]]:
"""Build the router_tool_use Dataset.
diff --git a/test/evals/datasets/routing.py b/test/evals/datasets/routing.py
index 455902f0110..826252ff98c 100644
--- a/test/evals/datasets/routing.py
+++ b/test/evals/datasets/routing.py
@@ -7,7 +7,6 @@ requires_galaxy=True need a running Galaxy session and are skipped by default.
from typing import (
Any,
- Optional,
)
from pydantic_evals import (
@@ -234,7 +233,7 @@ ROUTING_CASES: list[Case[str, str, dict[str, Any]]] = [
def routing_dataset(
include_galaxy_required: bool = False,
- only: Optional[list[str]] = None,
+ only: list[str] | None = None,
) -> Dataset[str, str, dict[str, Any]]:
"""Build the routing Dataset.
diff --git a/test/evals/datasets/routing_ambiguous.py b/test/evals/datasets/routing_ambiguous.py
index 09b7216ac41..58ee12189fe 100644
--- a/test/evals/datasets/routing_ambiguous.py
+++ b/test/evals/datasets/routing_ambiguous.py
@@ -18,7 +18,6 @@ import json
from pathlib import Path
from typing import (
Any,
- Optional,
)
from pydantic_evals import (
@@ -34,7 +33,7 @@ def _load_scenarios() -> list[dict[str, Any]]:
def routing_ambiguous_dataset(
- only: Optional[list[str]] = None,
+ only: list[str] | None = None,
) -> Dataset[str, str, dict[str, Any]]:
"""Build the ambiguous-routing Dataset: (vague query, expected="clarification")."""
cases: list[Case[str, str, dict[str, Any]]] = []
diff --git a/test/evals/datasets/routing_clarification_followup.py b/test/evals/datasets/routing_clarification_followup.py
index f2d0574890e..8ae6036fab7 100644
--- a/test/evals/datasets/routing_clarification_followup.py
+++ b/test/evals/datasets/routing_clarification_followup.py
@@ -20,7 +20,6 @@ import json
from pathlib import Path
from typing import (
Any,
- Optional,
)
from pydantic_evals import (
@@ -36,7 +35,7 @@ def _load_scenarios() -> list[dict[str, Any]]:
def routing_clarification_followup_dataset(
- only: Optional[list[str]] = None,
+ only: list[str] | None = None,
) -> Dataset[dict[str, Any], str, dict[str, Any]]:
"""Build the clarification-followup Dataset.
diff --git a/test/evals/datasets/routing_depth.py b/test/evals/datasets/routing_depth.py
index 422f28b6b04..14aa12bd2e9 100644
--- a/test/evals/datasets/routing_depth.py
+++ b/test/evals/datasets/routing_depth.py
@@ -21,7 +21,6 @@ import json
from pathlib import Path
from typing import (
Any,
- Optional,
)
from pydantic_evals import (
@@ -53,7 +52,7 @@ def _load_scenarios() -> list[dict[str, Any]]:
def routing_depth_dataset(
- only: Optional[list[str]] = None,
+ only: list[str] | None = None,
) -> Dataset[dict[str, Any], str, dict[str, Any]]:
"""Build the routing-depth Dataset. History representation is applied by the task."""
cases: list[Case[dict[str, Any], str, dict[str, Any]]] = []
diff --git a/test/evals/datasets/routing_followup.py b/test/evals/datasets/routing_followup.py
index bebfb6e961e..195a32d8a57 100644
--- a/test/evals/datasets/routing_followup.py
+++ b/test/evals/datasets/routing_followup.py
@@ -20,7 +20,6 @@ import json
from pathlib import Path
from typing import (
Any,
- Optional,
)
from pydantic_evals import (
@@ -36,7 +35,7 @@ def _load_scenarios() -> list[dict[str, Any]]:
def routing_followup_dataset(
- only: Optional[list[str]] = None,
+ only: list[str] | None = None,
) -> Dataset[dict[str, Any], str, dict[str, Any]]:
"""Build the followup Dataset.
diff --git a/test/evals/datasets/staining_quantification.py b/test/evals/datasets/staining_quantification.py
index db2f47e0260..40249d972cc 100644
--- a/test/evals/datasets/staining_quantification.py
+++ b/test/evals/datasets/staining_quantification.py
@@ -33,7 +33,6 @@ Notes:
from typing import (
Any,
- Optional,
)
from pydantic_ai.models import Model
@@ -216,8 +215,8 @@ Return a number; no commentary.
def staining_quantification_dataset(
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
) -> Dataset[str, str, dict[str, Any]]:
"""Build the staining_quantification Dataset.
diff --git a/test/evals/datasets/tool_recommendation.py b/test/evals/datasets/tool_recommendation.py
index 20a1e642455..5136039bfb6 100644
--- a/test/evals/datasets/tool_recommendation.py
+++ b/test/evals/datasets/tool_recommendation.py
@@ -18,7 +18,6 @@ search results come back. Not a substitute for an end-to-end test.
from typing import (
Any,
- Optional,
)
from pydantic_ai.models import Model
@@ -122,8 +121,8 @@ Return a number; no commentary.
def tool_recommendation_dataset(
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
) -> Dataset[str, str, dict[str, Any]]:
"""Build the tool_recommendation Dataset.
diff --git a/test/evals/run_evals.py b/test/evals/run_evals.py
index 1bf1ee81ae6..8a330b01143 100644
--- a/test/evals/run_evals.py
+++ b/test/evals/run_evals.py
@@ -31,7 +31,6 @@ from datetime import datetime
from pathlib import Path
from typing import (
Any,
- Optional,
)
import yaml
@@ -85,8 +84,7 @@ def _require_model_entry(model: str, model_config: dict[str, Any]) -> dict[str,
entry = model_config.get(model)
if not entry:
raise SystemExit(
- f"Model '{model}' is not declared in the model-config YAML. "
- f"Known: {', '.join(model_config) or '(none)'}."
+ f"Model '{model}' is not declared in the model-config YAML. Known: {', '.join(model_config) or '(none)'}."
)
return entry
@@ -108,8 +106,7 @@ def _resolve_api_key(model: str, model_config: dict[str, Any]) -> str:
entry = _require_model_entry(model, model_config)
if "api_key" in entry:
return entry["api_key"]
- api_key_env = entry.get("api_key_env")
- if api_key_env:
+ if api_key_env := entry.get("api_key_env"):
api_key = os.environ.get(api_key_env)
if not api_key:
raise SystemExit(f"Model '{model}' requires env var {api_key_env} (not set).")
@@ -117,7 +114,7 @@ def _resolve_api_key(model: str, model_config: dict[str, Any]) -> str:
raise SystemExit(f"Model '{model}' needs either api_key or api_key_env in the YAML.")
-def _load_model_config(path: Optional[str]) -> tuple[str, dict[str, Any]]:
+def _load_model_config(path: str | None) -> tuple[str, dict[str, Any]]:
"""Resolve the model-config YAML path and load it. Falls back to .sample.
Returns (path_used, parsed_dict).
@@ -190,7 +187,7 @@ def _score_pass_count(
return passed, total
-def _median_duration_s(report: EvaluationReport[Any, Any, Any]) -> Optional[float]:
+def _median_duration_s(report: EvaluationReport[Any, Any, Any]) -> float | None:
durations = [c.task_duration for c in report.cases if c.task_duration is not None]
return statistics.median(durations) if durations else None
@@ -207,7 +204,7 @@ def _all_score_names(reports: list[EvaluationReport[Any, Any, Any]]) -> list[str
return names
-def _base_case_name(name: Optional[str]) -> Optional[str]:
+def _base_case_name(name: str | None) -> str | None:
"""Strip pydantic-evals' " [N/M]" repeat suffix from a case name."""
if not name:
return name
@@ -341,7 +338,7 @@ def _render_dataset_section(results: list[DatasetResult]) -> str:
continue
ok_count = 0
judge_values: list[float] = []
- wrong_sample: Optional[str] = None
+ wrong_sample: str | None = None
pass_threshold = 0.7 if r.primary_score == "LLMJudge" else 1.0
for case in cases:
scores = case.scores or {}
@@ -389,7 +386,7 @@ def _render_dataset_section(results: list[DatasetResult]) -> str:
def render_markdown(
all_results: list["DatasetResult"],
- baseline: Optional[list["DatasetResult"]] = None,
+ baseline: list["DatasetResult"] | None = None,
) -> str:
"""Render a single markdown document covering every dataset evaluated."""
by_dataset: dict[str, list[DatasetResult]] = {}
@@ -585,7 +582,7 @@ async def run_eval_suite(
model_config: dict[str, dict[str, str]],
judge_model_name: str,
deps_factory: DepsFactory,
- only: Optional[list[str]] = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
max_concurrency: int = 4,
repeat: int = 1,
@@ -645,7 +642,7 @@ def write_eval_report(
results: list[DatasetResult],
datasets: list[str],
results_dir: Path,
- baseline_path: Optional[Path] = None,
+ baseline_path: Path | None = None,
) -> tuple[Path, Path]:
"""Render markdown + JSON and write to results_dir. Returns (md_path, json_path)."""
baseline = _load_baseline(str(baseline_path)) if baseline_path else None
diff --git a/test/evals/seed_staining_quantification_history.py b/test/evals/seed_staining_quantification_history.py
index 27cf95587e1..4d1967b57ea 100644
--- a/test/evals/seed_staining_quantification_history.py
+++ b/test/evals/seed_staining_quantification_history.py
@@ -36,7 +36,6 @@ import io
import sys
from typing import (
Any,
- Optional,
)
HISTORY_NAME = "Staining quantification (eval fixture)"
@@ -135,7 +134,7 @@ def seed_demo_history(dataset_populator: Any) -> str:
return history_id
-def _standalone_main(argv: Optional[list[str]] = None) -> int:
+def _standalone_main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--galaxy-url", required=True, help="Base URL of the running Galaxy.")
parser.add_argument("--galaxy-api-key", required=True, help="API key for the user to seed for.")
diff --git a/test/evals/specs.py b/test/evals/specs.py
index 4a3f289dfe8..c7e27e6d543 100644
--- a/test/evals/specs.py
+++ b/test/evals/specs.py
@@ -11,7 +11,6 @@ from dataclasses import dataclass
from typing import (
Any,
Generic,
- Optional,
TypeVar,
)
@@ -74,10 +73,10 @@ class BuiltDataset(Generic[CaseInputsT]):
def build_routing(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
dataset = routing_dataset(include_galaxy_required=include_galaxy_required, only=only)
dataset.add_evaluator(HandoffMatch())
@@ -91,8 +90,8 @@ def build_routing(
def _build_routing_depth(
deps: GalaxyAgentDependencies,
representation: str,
- only: Optional[list[str]],
- usage_buffer: Optional[list[dict[str, int]]],
+ only: list[str] | None,
+ usage_buffer: list[dict[str, int]] | None,
) -> BuiltDataset:
dataset = routing_depth_dataset(only=only)
dataset.add_evaluator(HandoffMatch())
@@ -105,10 +104,10 @@ def _build_routing_depth(
def build_routing_depth_turn1(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
"""Turn-1 baseline: the final query with no conversation history."""
return _build_routing_depth(deps, "none", only, usage_buffer)
@@ -116,10 +115,10 @@ def build_routing_depth_turn1(
def build_routing_depth_prose(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
"""Deep conversation as flattened prose. The router routes on the current message, so
this should recover to ~the turn-1 baseline rather than degrading."""
@@ -128,10 +127,10 @@ def build_routing_depth_prose(
def build_routing_ambiguous(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
"""Genuinely-ambiguous queries; expected route is "clarification" (ask, don't guess)."""
dataset = routing_ambiguous_dataset(only=only)
@@ -146,8 +145,8 @@ def build_routing_ambiguous(
def _build_routing_clarification_followup(
deps: GalaxyAgentDependencies,
responding_to_clarification: bool,
- only: Optional[list[str]],
- usage_buffer: Optional[list[dict[str, int]]],
+ only: list[str] | None,
+ usage_buffer: list[dict[str, int]] | None,
) -> BuiltDataset:
dataset = routing_clarification_followup_dataset(only=only)
dataset.add_evaluator(HandoffMatch())
@@ -162,10 +161,10 @@ def _build_routing_clarification_followup(
def build_routing_clarification_followup(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
"""Route the answer to a clarifying question WITH the seam fix (the shipped behavior):
the router sees the prior turn, so "the second one" routes to the right specialist."""
@@ -174,10 +173,10 @@ def build_routing_clarification_followup(
def build_routing_clarification_followup_nofix(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
"""A/B control: route the same answers WITHOUT the seam (history withheld). The elliptical
answers have no referent, so this should score well below the fixed variant -- that gap is
@@ -188,8 +187,8 @@ def build_routing_clarification_followup_nofix(
def _build_routing_followup(
deps: GalaxyAgentDependencies,
route_followup: bool,
- only: Optional[list[str]],
- usage_buffer: Optional[list[dict[str, int]]],
+ only: list[str] | None,
+ usage_buffer: list[dict[str, int]] | None,
) -> BuiltDataset:
dataset = routing_followup_dataset(only=only)
dataset.add_evaluator(HandoffMatch())
@@ -202,10 +201,10 @@ def _build_routing_followup(
def build_routing_followup(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
"""Route a follow-up to a normal answer WITH the fix (the shipped behavior): the router
sees the prior user turn, so "what about a workflow for this?" routes to the right
@@ -215,10 +214,10 @@ def build_routing_followup(
def build_routing_followup_nofix(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
"""A/B control: route the same follow-ups WITHOUT the fix (prior user turn withheld). The
elliptical follow-up has no referent, so this should score well below the fixed variant --
@@ -228,10 +227,10 @@ def build_routing_followup_nofix(
def build_error_analysis(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
dataset = error_analysis_dataset(judge_model=judge_model, only=only)
dataset.add_evaluator(MustMention())
@@ -244,10 +243,10 @@ def build_error_analysis(
def build_tool_recommendation(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
dataset = tool_recommendation_dataset(judge_model=judge_model, only=only)
dataset.add_evaluator(MustMentionAny())
@@ -260,10 +259,10 @@ def build_tool_recommendation(
def build_custom_tool(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
dataset = custom_tool_dataset(judge_model=judge_model, only=only)
# Headline pass/fail + the "got it right first try" and structural-shape checks.
@@ -279,10 +278,10 @@ def build_custom_tool(
def build_router_tool_use(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
dataset = router_tool_use_dataset(only=only)
dataset.add_evaluator(ToolCallMatch())
@@ -295,10 +294,10 @@ def build_router_tool_use(
def build_bioinformatics_workflows(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
dataset = bioinformatics_workflows_dataset(judge_model=judge_model, only=only)
return BuiltDataset(
@@ -310,10 +309,10 @@ def build_bioinformatics_workflows(
def build_capabilities(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
"""Groundedness of the router's "what can you do?" answer (no action over-claims)."""
dataset = capabilities_dataset(judge_model=judge_model, only=only)
@@ -326,10 +325,10 @@ def build_capabilities(
def build_staining_quantification(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
dataset = staining_quantification_dataset(
judge_model=judge_model,
@@ -345,10 +344,10 @@ def build_staining_quantification(
def build_orchestrator_planning(
deps: GalaxyAgentDependencies,
- judge_model: Optional[Model] = None,
- only: Optional[list[str]] = None,
+ judge_model: Model | None = None,
+ only: list[str] | None = None,
include_galaxy_required: bool = False,
- usage_buffer: Optional[list[dict[str, int]]] = None,
+ usage_buffer: list[dict[str, int]] | None = None,
) -> BuiltDataset:
dataset = orchestrator_planning_dataset(only=only)
dataset.add_evaluator(OrchestratorPlanIncludes())
diff --git a/test/evals/tasks.py b/test/evals/tasks.py
index 818e215ce07..899ef1ad252 100644
--- a/test/evals/tasks.py
+++ b/test/evals/tasks.py
@@ -13,7 +13,6 @@ from collections.abc import (
from typing import (
Any,
cast,
- Optional,
TYPE_CHECKING,
)
from unittest.mock import MagicMock
@@ -33,7 +32,7 @@ from galaxy.agents.router import QueryRouterAgent
from galaxy.agents.tools import ToolRecommendationAgent
from .datasets import build_history
-UsageBuffer = Optional[list[dict[str, int]]]
+UsageBuffer = list[dict[str, int]] | None
def _record_response_usage(buffer: UsageBuffer, response: Any) -> None:
@@ -185,7 +184,7 @@ def make_live_deps(
def make_router_task(
deps: GalaxyAgentDependencies,
- context: Optional[dict] = None,
+ context: dict | None = None,
usage_buffer: UsageBuffer = None,
) -> Callable[[str], Awaitable[str]]:
"""Build an async callable: query -> router's chosen agent_type."""
@@ -292,7 +291,7 @@ def make_router_followup_task(
def make_router_content_task(
deps: GalaxyAgentDependencies,
- context: Optional[dict] = None,
+ context: dict | None = None,
usage_buffer: UsageBuffer = None,
) -> Callable[[str], Awaitable[str]]:
"""Build an async callable: query -> router final response content.
@@ -314,7 +313,7 @@ def make_router_content_task(
def make_error_analysis_task(
deps: GalaxyAgentDependencies,
- context: Optional[dict] = None,
+ context: dict | None = None,
usage_buffer: UsageBuffer = None,
) -> Callable[[str], Awaitable[str]]:
"""Build an async callable: query -> error-analysis response content."""
@@ -330,7 +329,7 @@ def make_error_analysis_task(
def make_tool_recommendation_task(
deps: GalaxyAgentDependencies,
- context: Optional[dict] = None,
+ context: dict | None = None,
usage_buffer: UsageBuffer = None,
) -> Callable[[str], Awaitable[str]]:
"""Build an async callable: query -> tool-recommendation response content.
@@ -354,7 +353,7 @@ def make_tool_recommendation_task(
def make_custom_tool_task(
deps: GalaxyAgentDependencies,
- context: Optional[dict] = None,
+ context: dict | None = None,
usage_buffer: UsageBuffer = None,
) -> Callable[[str], Awaitable[dict[str, Any]]]:
"""Build an async callable: NL request -> custom-tool generation result dict.
@@ -413,7 +412,7 @@ def _extract_tool_calls(result: Any) -> list[dict[str, Any]]:
def make_orchestrator_plan_task(
deps: GalaxyAgentDependencies,
- context: Optional[dict] = None,
+ context: dict | None = None,
usage_buffer: UsageBuffer = None,
) -> Callable[[str], Awaitable[dict[str, Any]]]:
"""Build an async callable: query -> {"agent_type": str, "agents_used": list[str]}.
@@ -451,7 +450,7 @@ def make_orchestrator_plan_task(
def make_router_inspect_task(
deps: GalaxyAgentDependencies,
- context: Optional[dict] = None,
+ context: dict | None = None,
usage_buffer: UsageBuffer = None,
) -> Callable[[str], Awaitable[dict[str, Any]]]:
"""Build an async callable: query -> {"content": str, "tool_calls": list}.
diff --git a/test/integration/htcondor_fake/htcondor2.py b/test/integration/htcondor_fake/htcondor2.py
index ccc67f6df93..60807678694 100644
--- a/test/integration/htcondor_fake/htcondor2.py
+++ b/test/integration/htcondor_fake/htcondor2.py
@@ -69,8 +69,7 @@ def _create_job_log(submit_description: str) -> str | None:
def _mark_job_pending(submit_description: str, cluster_id: int) -> None:
- log_path = _create_job_log(submit_description)
- if log_path:
+ if log_path := _create_job_log(submit_description):
JobEventLog.events_by_log[log_path] = [
FakeJobEvent(cluster_id, 0, JobEventType.SUBMIT),
FakeJobEvent(cluster_id, 0, JobEventType.EXECUTE),
diff --git a/test/integration/objectstore/test_bulk_storage_operations.py b/test/integration/objectstore/test_bulk_storage_operations.py
index 422a08bcdd7..e6e7008f0c9 100644
--- a/test/integration/objectstore/test_bulk_storage_operations.py
+++ b/test/integration/objectstore/test_bulk_storage_operations.py
@@ -31,7 +31,6 @@ from types import SimpleNamespace
from typing import (
Any,
cast,
- Optional,
)
from unittest.mock import patch
from uuid import uuid4
@@ -338,7 +337,7 @@ class TestBulkStorageOperationsIntegration(BaseObjectStoreIntegrationTestCase):
succeeded: int,
failed: int,
skipped: int,
- total_bytes_processed: Optional[int] = None,
+ total_bytes_processed: int | None = None,
state: str = "completed",
mode: str = "move",
) -> None:
@@ -874,8 +873,7 @@ class TestBulkStorageOperationsIntegration(BaseObjectStoreIntegrationTestCase):
original_flush = executor._flush_pending_dataset_updates
def recording_flush():
- pending_count = len(executor._pending_dataset_update_ids)
- if pending_count:
+ if pending_count := len(executor._pending_dataset_update_ids):
batch_sizes.append(pending_count)
return original_flush()
diff --git a/test/integration/objectstore/test_objectstore_datatype_upload.py b/test/integration/objectstore/test_objectstore_datatype_upload.py
index da80d324afb..995da792078 100644
--- a/test/integration/objectstore/test_objectstore_datatype_upload.py
+++ b/test/integration/objectstore/test_objectstore_datatype_upload.py
@@ -4,7 +4,6 @@ import os
import string
import subprocess
import time
-from typing import Optional
import pytest
@@ -114,7 +113,7 @@ def stop_irods(container_name):
class BaseObjectstoreUploadIntegrationInstance(UploadTestDatatypeDataIntegrationInstance):
- object_store_template: Optional[string.Template] = None
+ object_store_template: string.Template | None = None
@classmethod
def handle_galaxy_config_kwds(cls, config):
diff --git a/test/integration/objectstore/test_remote_objectstore_cache_operations.py b/test/integration/objectstore/test_remote_objectstore_cache_operations.py
index cf3c9391a1a..06f61742441 100644
--- a/test/integration/objectstore/test_remote_objectstore_cache_operations.py
+++ b/test/integration/objectstore/test_remote_objectstore_cache_operations.py
@@ -47,14 +47,14 @@ class TestCacheOperation(BaseSwiftObjectStoreIntegrationTestCase):
hda = self.upload_bam_dataset()
assert files_count(self.object_store_cache_path) == 2
response = self._get(
- f'histories/{hda["history_id"]}/contents/{hda["id"]}/metadata_file?metadata_file=bam_index'
+ f"histories/{hda['history_id']}/contents/{hda['id']}/metadata_file?metadata_file=bam_index"
)
assert len(response.content) > 0
response.raise_for_status()
shutil.rmtree(self.object_store_cache_path)
assert files_count(self.object_store_cache_path) == 0
response = self._get(
- f'histories/{hda["history_id"]}/contents/{hda["id"]}/metadata_file?metadata_file=bam_index'
+ f"histories/{hda['history_id']}/contents/{hda['id']}/metadata_file?metadata_file=bam_index"
)
response.raise_for_status()
assert files_count(self.object_store_cache_path) == 1
diff --git a/test/integration/objectstore/test_rucio_objectstore.py b/test/integration/objectstore/test_rucio_objectstore.py
index 763605debf3..6201f13f877 100644
--- a/test/integration/objectstore/test_rucio_objectstore.py
+++ b/test/integration/objectstore/test_rucio_objectstore.py
@@ -28,7 +28,6 @@ TEST_TOOL_IDS = [
class TestRucioObjectStoreIntegration(BaseRucioObjectStoreIntegrationTestCase):
-
@classmethod
def handle_galaxy_config_kwds(cls, config):
super().handle_galaxy_config_kwds(config)
diff --git a/test/integration/objectstore/test_selection_with_user_preferred_object_store.py b/test/integration/objectstore/test_selection_with_user_preferred_object_store.py
index 673304e8f8b..1ed00c92896 100644
--- a/test/integration/objectstore/test_selection_with_user_preferred_object_store.py
+++ b/test/integration/objectstore/test_selection_with_user_preferred_object_store.py
@@ -4,7 +4,6 @@ import os
import string
from typing import (
Any,
- Optional,
)
from sqlalchemy import select
@@ -433,7 +432,7 @@ class TestObjectStoreSelectionWithPreferredObjectStoresIntegration(BaseObjectSto
history_id: str,
workflow: str,
test_data: str,
- extra_invocation_kwds: Optional[dict[str, Any]] = None,
+ extra_invocation_kwds: dict[str, Any] | None = None,
):
self.workflow_populator.run_workflow(
workflow,
@@ -453,7 +452,7 @@ class TestObjectStoreSelectionWithPreferredObjectStoresIntegration(BaseObjectSto
assert len(elements) > 0, "Collection has no elements"
return [self._storage_info(element["object"]) for element in elements]
- def _run_workflow_with_collections_1(self, history_id: str, extra_invocation_kwds: Optional[dict[str, Any]] = None):
+ def _run_workflow_with_collections_1(self, history_id: str, extra_invocation_kwds: dict[str, Any] | None = None):
wf_run = self.workflow_populator.run_workflow(
WORKFLOW_WITH_COLLECTIONS_1,
test_data=WORKFLOW_WITH_COLLECTIONS_1_TEST_DATA,
@@ -472,7 +471,7 @@ class TestObjectStoreSelectionWithPreferredObjectStoresIntegration(BaseObjectSto
output_info = self._storage_info(objects[0])
return intermediate_info, output_info
- def _run_workflow_with_collections_2(self, history_id: str, extra_invocation_kwds: Optional[dict[str, Any]] = None):
+ def _run_workflow_with_collections_2(self, history_id: str, extra_invocation_kwds: dict[str, Any] | None = None):
wf_run = self.workflow_populator.run_workflow(
WORKFLOW_WITH_COLLECTIONS_2,
test_data=WORKFLOW_WITH_COLLECTIONS_1_TEST_DATA,
@@ -492,7 +491,7 @@ class TestObjectStoreSelectionWithPreferredObjectStoresIntegration(BaseObjectSto
return intermediate_info, output_info
def _run_simple_nested_workflow_get_output_storage_info_dicts(
- self, history_id: str, extra_invocation_kwds: Optional[dict[str, Any]] = None
+ self, history_id: str, extra_invocation_kwds: dict[str, Any] | None = None
):
wf_run = self.workflow_populator.run_workflow(
WORKFLOW_NESTED_SIMPLE,
@@ -512,7 +511,7 @@ class TestObjectStoreSelectionWithPreferredObjectStoresIntegration(BaseObjectSto
return output_info, intermediate_info
def _run_nested_workflow_with_effective_output_get_output_storage_info_dicts(
- self, history_id: str, extra_invocation_kwds: Optional[dict[str, Any]] = None, twice_nested=False
+ self, history_id: str, extra_invocation_kwds: dict[str, Any] | None = None, twice_nested=False
):
workflow_data = WORKFLOW_NESTED_OUTPUT if not twice_nested else WORKFLOW_NESTED_TWICE_OUTPUT
wf_run = self.workflow_populator.run_workflow(
@@ -532,7 +531,7 @@ class TestObjectStoreSelectionWithPreferredObjectStoresIntegration(BaseObjectSto
return output_info, intermediate_info
def _run_workflow_get_output_storage_info_dicts(
- self, history_id: str, extra_invocation_kwds: Optional[dict[str, Any]] = None
+ self, history_id: str, extra_invocation_kwds: dict[str, Any] | None = None
):
wf_run = self.workflow_populator.run_workflow(
TEST_WORKFLOW,
@@ -562,7 +561,7 @@ class TestObjectStoreSelectionWithPreferredObjectStoresIntegration(BaseObjectSto
def _storage_info(self, hda):
return self.dataset_populator.dataset_storage_info(hda["id"])
- def _set_user_preferred_object_store_id(self, store_id: Optional[str]) -> None:
+ def _set_user_preferred_object_store_id(self, store_id: str | None) -> None:
self.dataset_populator.set_user_preferred_object_store_id(store_id)
def _reset_user_preferred_object_store_id(self):
diff --git a/test/integration/oidc/test_auth_oidc.py b/test/integration/oidc/test_auth_oidc.py
index 910a7ac89ce..9bd511484fa 100644
--- a/test/integration/oidc/test_auth_oidc.py
+++ b/test/integration/oidc/test_auth_oidc.py
@@ -9,7 +9,6 @@ import time
from string import Template
from typing import (
ClassVar,
- Union,
)
from unittest.mock import (
_patch,
@@ -111,7 +110,7 @@ class AbstractTestCases:
container_name: ClassVar[str]
backend_config_file: ClassVar[str]
provider_name: ClassVar[str]
- saved_env_vars: ClassVar[dict[str, Union[str, None]]]
+ saved_env_vars: ClassVar[dict[str, str | None]]
config_patcher: ClassVar[_patch]
@classmethod
diff --git a/test/integration/test_celery_user_concurrency_limit.py b/test/integration/test_celery_user_concurrency_limit.py
index 6aef292f1a9..d89b091af00 100644
--- a/test/integration/test_celery_user_concurrency_limit.py
+++ b/test/integration/test_celery_user_concurrency_limit.py
@@ -2,7 +2,6 @@ import datetime
import tempfile
import time
from functools import lru_cache
-from typing import Optional
from celery.result import AsyncResult
from sqlalchemy import (
@@ -25,7 +24,7 @@ from galaxy_test.driver.integration_util import (
def mock_sleep_task(
session: galaxy_scoped_session,
sleep_seconds: float = 2.0,
- task_user_id: Optional[int] = None,
+ task_user_id: int | None = None,
):
"""Task that sleeps for a configurable duration, used to test concurrency limits."""
time.sleep(sleep_seconds)
@@ -117,10 +116,9 @@ class TestCeleryUserConcurrencyLimitIntegration(IntegrationTestCase):
expected_min = sleep_seconds * (num_tasks / self._concurrency_limit) - 1
# Allow generous upper bound for scheduling overhead
expected_max = sleep_seconds * (num_tasks / self._concurrency_limit) + 15
- assert elapsed >= expected_min, (
- f"Tasks completed too fast ({elapsed:.1f}s < {expected_min:.1f}s), "
- f"concurrency limit may not be enforced"
- )
+ assert (
+ elapsed >= expected_min
+ ), f"Tasks completed too fast ({elapsed:.1f}s < {expected_min:.1f}s), concurrency limit may not be enforced"
assert elapsed <= expected_max, f"Tasks took too long ({elapsed:.1f}s > {expected_max:.1f}s)"
def _test_different_users_independent(self):
diff --git a/test/integration/test_container_resolvers.py b/test/integration/test_container_resolvers.py
index 0e75b1feaa6..42ce895828d 100644
--- a/test/integration/test_container_resolvers.py
+++ b/test/integration/test_container_resolvers.py
@@ -5,7 +5,6 @@ from typing import (
Any,
ClassVar,
Literal,
- Optional,
TYPE_CHECKING,
)
@@ -66,7 +65,7 @@ JOB_CONFIG_FOR_CONTAINER_TYPE = {
def _assert_container_in_cache_docker(
- cached: bool, container_name: str, namespace: Optional[str] = None, hash_func: Literal["v1", "v2"] = "v2"
+ cached: bool, container_name: str, namespace: str | None = None, hash_func: Literal["v1", "v2"] = "v2"
):
cache_list = list_docker_cached_mulled_images(namespace, hash_func)
imageid_list = [_.image_identifier for _ in cache_list]
@@ -154,7 +153,7 @@ class DockerContainerResolverTestCase(IntegrationTestCase):
config["conda_prefix"] = os.path.join(cls.conda_tmp_prefix, "conda")
def _remove_tested_docker_image_from_cache(self):
- cmd1 = ["docker", "image", "ls", "--quiet", "--filter", f'reference={self.assumptions["run"]["cache_name"]}']
+ cmd1 = ["docker", "image", "ls", "--quiet", "--filter", f"reference={self.assumptions['run']['cache_name']}"]
if image_ids := execute(cmd1):
image_id_list = image_ids.splitlines()
assert len(image_id_list) == 1
@@ -171,7 +170,7 @@ class DockerContainerResolverTestCase(IntegrationTestCase):
self,
cached: bool,
container_name: str,
- namespace: Optional[str] = None,
+ namespace: str | None = None,
hash_func: Literal["v1", "v2"] = "v2",
**kwargs,
) -> None:
@@ -192,7 +191,7 @@ class DockerContainerResolverTestCase(IntegrationTestCase):
self,
cached: bool,
container_name: str,
- namespace: Optional[str] = None,
+ namespace: str | None = None,
hash_func: Literal["v1", "v2"] = "v2",
**kwargs,
):
@@ -217,7 +216,7 @@ class SingularityContainerResolverTestCase(DockerContainerResolverTestCase):
self,
cached: bool,
container_name: str,
- namespace: Optional[str] = None,
+ namespace: str | None = None,
hash_func: Literal["v1", "v2"] = "v2",
**kwargs,
) -> None:
@@ -278,7 +277,7 @@ class ContainerResolverTestProtocol(Protocol):
self,
cached: bool,
container_name: str,
- namespace: Optional[str] = None,
+ namespace: str | None = None,
hash_func: Literal["v1", "v2"] = "v2",
**kwargs,
) -> None:
@@ -291,7 +290,7 @@ class ContainerResolverTestProtocol(Protocol):
self,
cached: bool,
container_name: str,
- namespace: Optional[str] = None,
+ namespace: str | None = None,
hash_func: Literal["v1", "v2"] = "v2",
**kwargs,
) -> None:
@@ -608,7 +607,7 @@ class TestDefaultSingularityContainerResolvers(
self,
cached: bool,
container_name: str,
- namespace: Optional[str] = None,
+ namespace: str | None = None,
hash_func: Literal["v1", "v2"] = "v2",
**kwargs,
) -> None:
diff --git a/test/integration/test_credentials.py b/test/integration/test_credentials.py
index e7cfb039b63..50ecb88844e 100644
--- a/test/integration/test_credentials.py
+++ b/test/integration/test_credentials.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from galaxy.model.db.user import get_user_by_email
from galaxy.security.vault import UserVaultWrapper
from galaxy_test.base.api_util import random_name
@@ -524,7 +522,7 @@ class TestCredentialsApi(integration_util.IntegrationTestCase, integration_util.
return list_user_credentials
def _check_vault_entry_exists(
- self, user_email: str, vault_ref: str, expected_value: Optional[str] = None, should_exist=True
+ self, user_email: str, vault_ref: str, expected_value: str | None = None, should_exist=True
):
app = self._app
user = get_user_by_email(app.model.session, user_email)
diff --git a/test/integration/test_dataset_hashing.py b/test/integration/test_dataset_hashing.py
index a3a123b735f..f022f5cb268 100644
--- a/test/integration/test_dataset_hashing.py
+++ b/test/integration/test_dataset_hashing.py
@@ -1,12 +1,10 @@
-from typing import Optional
-
from galaxy_test.base.populators import DatasetPopulator
from galaxy_test.driver import integration_util
class TestDatasetHashingIntegration(integration_util.IntegrationTestCase):
dataset_populator: DatasetPopulator
- calculate_dataset_hash: Optional[str] = None
+ calculate_dataset_hash: str | None = None
def setUp(self) -> None:
super().setUp()
diff --git a/test/integration/test_default_permissions.py b/test/integration/test_default_permissions.py
index 1580f3d0835..21e75356746 100644
--- a/test/integration/test_default_permissions.py
+++ b/test/integration/test_default_permissions.py
@@ -1,12 +1,10 @@
-from typing import Optional
-
from galaxy_test.base.populators import DatasetPopulator
from galaxy_test.driver import integration_util
class TestDefaultPermissionsIntegration(integration_util.IntegrationTestCase):
dataset_populator: DatasetPopulator
- new_user_dataset_access_role_default_private: Optional[bool] = None
+ new_user_dataset_access_role_default_private: bool | None = None
expected_access_status_code = 200
def setUp(self) -> None:
diff --git a/test/integration/test_event_loop_blocking.py b/test/integration/test_event_loop_blocking.py
index afcc82e5c28..29331eb1c8c 100644
--- a/test/integration/test_event_loop_blocking.py
+++ b/test/integration/test_event_loop_blocking.py
@@ -64,8 +64,7 @@ class TestAiocopBlockingDetection(integration_util.IntegrationTestCase):
response = self._get("debug/ok")
self._assert_status_code_is(response, 200)
assert response.json()["status"] == "ok"
- header = response.headers.get("x-aiocop-violations", "")
- if header:
+ if header := response.headers.get("x-aiocop-violations", ""):
fields = dict(p.split("=", 1) for p in header.split(";") if "=" in p)
assert (
int(fields.get("severity", "0")) < 50
diff --git a/test/integration/test_hashicorp_vault.py b/test/integration/test_hashicorp_vault.py
index 1fe657553c5..261c52c8e0b 100644
--- a/test/integration/test_hashicorp_vault.py
+++ b/test/integration/test_hashicorp_vault.py
@@ -80,10 +80,7 @@ def _write_vault_config(vault_addr, vault_token, path_prefix="/galaxy_integratio
fd, path = tempfile.mkstemp(prefix="vault_hashicorp_integ_", suffix=".yml")
with os.fdopen(fd, "w") as f:
f.write(
- f"type: hashicorp\n"
- f"path_prefix: {path_prefix}\n"
- f"vault_address: {vault_addr}\n"
- f"vault_token: {vault_token}\n"
+ f"type: hashicorp\npath_prefix: {path_prefix}\nvault_address: {vault_addr}\nvault_token: {vault_token}\n"
)
return path
diff --git a/test/integration/test_history_archiving.py b/test/integration/test_history_archiving.py
index dcdabb6feb2..2f9bd1dae37 100644
--- a/test/integration/test_history_archiving.py
+++ b/test/integration/test_history_archiving.py
@@ -1,5 +1,4 @@
from datetime import datetime
-from typing import Optional
from uuid import uuid4
from sqlalchemy import text
@@ -221,7 +220,7 @@ class TestHistoryArchivingWithExportRecord(PosixFileSourceSetup, IntegrationTest
def _export_history_to_permanent_storage(
self,
history_id: str,
- target_uri: Optional[str] = None,
+ target_uri: str | None = None,
model_store_format: ModelStoreFormat = ModelStoreFormat.ROCRATE_ZIP,
):
target_uri = (
diff --git a/test/integration/test_history_sse.py b/test/integration/test_history_sse.py
index b412859de4a..c1eb1a2f92a 100644
--- a/test/integration/test_history_sse.py
+++ b/test/integration/test_history_sse.py
@@ -111,10 +111,9 @@ class TestHistorySSEIntegration(IntegrationTestCase):
seen_b_after_unsub = any(
user_b_history_id in json.loads(e["data"]).get("history_ids", []) for e in after_events
)
- assert not seen_b_after_unsub, (
- "User A still received history_update events for User B's history "
- f"after unsubscribing: {after_events}"
- )
+ assert (
+ not seen_b_after_unsub
+ ), f"User A still received history_update events for User B's history after unsubscribing: {after_events}"
finally:
listener.stop()
diff --git a/test/integration/test_interactivetools_api.py b/test/integration/test_interactivetools_api.py
index 2f4263c0da6..fdda2a8d9a3 100644
--- a/test/integration/test_interactivetools_api.py
+++ b/test/integration/test_interactivetools_api.py
@@ -3,7 +3,6 @@
import os
from typing import (
Any,
- Optional,
)
import pytest
@@ -43,7 +42,7 @@ class AbstractTestCases:
# Move helpers to populators.py
def wait_on_proxied_content(self, target: str) -> str:
- def get_hosted_content() -> Optional[str]:
+ def get_hosted_content() -> str | None:
try:
scheme, rest = target.split("://", 1)
prefix, host_and_port = rest.split(".interactivetool.")
@@ -69,7 +68,7 @@ class AbstractTestCases:
return access_json["target"]
def wait_on_entry_points_active(self, job_id: str, expected_num: int = 1) -> list[dict[str, Any]]:
- def active_entry_points() -> Optional[list[dict[str, Any]]]:
+ def active_entry_points() -> list[dict[str, Any]] | None:
entry_points = self.entry_points_for_job(job_id)
if len(entry_points) != expected_num:
return None
@@ -122,7 +121,7 @@ class AbstractTestCases:
content1 = self.wait_on_proxied_content(target1)
assert content1 == "moo cow\n", content1
- stop_response = self.dataset_populator._delete(f'entry_points/{entry_point0["id"]}')
+ stop_response = self.dataset_populator._delete(f"entry_points/{entry_point0['id']}")
stop_response.raise_for_status()
self.dataset_populator.wait_for_job(job0["id"], assert_ok=True)
job_details_response = self.dataset_populator.get_job_details(job0["id"], full=True)
diff --git a/test/integration/test_kubernetes_runner.py b/test/integration/test_kubernetes_runner.py
index 0b9dbbe119f..fa56ecb2da4 100644
--- a/test/integration/test_kubernetes_runner.py
+++ b/test/integration/test_kubernetes_runner.py
@@ -12,7 +12,6 @@ import tempfile
import time
from typing import (
Literal,
- Optional,
overload,
)
@@ -325,9 +324,9 @@ class TestKubernetesIntegration(BaseJobEnvironmentIntegrationTestCase, MulledJob
def get_kubectl_logs(allow_wait: Literal[False]) -> str: ...
@overload
- def get_kubectl_logs(allow_wait: bool = True) -> Optional[str]: ...
+ def get_kubectl_logs(allow_wait: bool = True) -> str | None: ...
- def get_kubectl_logs(allow_wait: bool = True) -> Optional[str]:
+ def get_kubectl_logs(allow_wait: bool = True) -> str | None:
log_cmd = ["kubectl", "logs", "-l", f"job-name={external_id}"]
p = subprocess.run(log_cmd, capture_output=True, text=True)
if p.returncode:
diff --git a/test/integration/test_landing_requests.py b/test/integration/test_landing_requests.py
index 0fd093333a7..fae4b271119 100644
--- a/test/integration/test_landing_requests.py
+++ b/test/integration/test_landing_requests.py
@@ -1,6 +1,5 @@
from typing import (
cast,
- Optional,
)
from sqlalchemy import select
@@ -140,11 +139,11 @@ class BaseLandingRequestTest(integration_util.IntegrationTestCase, integration_u
def _get_landing_request_from_db(
self, uuid: str, model_class: type[LandingRequestModel]
- ) -> Optional[LandingRequestModel]:
+ ) -> LandingRequestModel | None:
"""Get a landing request from the database by UUID."""
session = self._app.model.session
stmt = select(model_class).where(model_class.uuid == uuid)
- return cast(Optional[LandingRequestModel], session.execute(stmt).scalar_one_or_none())
+ return cast(LandingRequestModel | None, session.execute(stmt).scalar_one_or_none())
def _create_and_make_public_workflow(self, workflow_name: str) -> str:
"""Create a simple workflow and make it public."""
diff --git a/test/integration/test_notification_sse.py b/test/integration/test_notification_sse.py
index 7ec3bf7f2e5..38a7d8f77b3 100644
--- a/test/integration/test_notification_sse.py
+++ b/test/integration/test_notification_sse.py
@@ -1,7 +1,6 @@
"""Integration tests for the notification SSE (Server-Sent Events) endpoint."""
import json
-from typing import Optional
from urllib.parse import urljoin
from uuid import uuid4
@@ -10,7 +9,7 @@ from galaxy_test.base.sse import SSELineListener
from galaxy_test.driver.integration_util import IntegrationTestCase
-def notification_test_data(subject: Optional[str] = None, message: Optional[str] = None) -> dict:
+def notification_test_data(subject: str | None = None, message: str | None = None) -> dict:
return {
"source": "integration_tests",
"variant": "info",
@@ -23,7 +22,7 @@ def notification_test_data(subject: Optional[str] = None, message: Optional[str]
}
-def notification_broadcast_test_data(subject: Optional[str] = None, message: Optional[str] = None) -> dict:
+def notification_broadcast_test_data(subject: str | None = None, message: str | None = None) -> dict:
return {
"source": "integration_tests",
"variant": "info",
diff --git a/test/integration/test_notifications.py b/test/integration/test_notifications.py
index e311ff3bcf0..72351d42760 100644
--- a/test/integration/test_notifications.py
+++ b/test/integration/test_notifications.py
@@ -4,7 +4,6 @@ from datetime import (
)
from typing import (
Any,
- Optional,
)
from uuid import uuid4
@@ -16,7 +15,7 @@ from galaxy_test.base.populators import (
from galaxy_test.driver.integration_util import IntegrationTestCase
-def notification_test_data(subject: Optional[str] = None, message: Optional[str] = None):
+def notification_test_data(subject: str | None = None, message: str | None = None):
return {
"source": "integration_tests",
"variant": "info",
@@ -29,7 +28,7 @@ def notification_test_data(subject: Optional[str] = None, message: Optional[str]
}
-def notification_broadcast_test_data(subject: Optional[str] = None, message: Optional[str] = None):
+def notification_broadcast_test_data(subject: str | None = None, message: str | None = None):
return {
"source": "integration_tests",
"variant": "info",
@@ -378,9 +377,7 @@ class NotificationsIntegrationBase(IntegrationTestCase):
status = status_response.json()
return status
- def _send_test_notification_to(
- self, user_ids: list[str], subject: Optional[str] = None, message: Optional[str] = None
- ):
+ def _send_test_notification_to(self, user_ids: list[str], subject: str | None = None, message: str | None = None):
request = {
"recipients": {"user_ids": user_ids},
"notification": notification_test_data(subject, message),
@@ -392,11 +389,11 @@ class NotificationsIntegrationBase(IntegrationTestCase):
def _send_broadcast_notification(
self,
- subject: Optional[str] = None,
- message: Optional[str] = None,
- publication_time: Optional[datetime] = None,
- expiration_time: Optional[datetime] = None,
- action_links: Optional[list[tuple[str, str]]] = None,
+ subject: str | None = None,
+ message: str | None = None,
+ publication_time: datetime | None = None,
+ expiration_time: datetime | None = None,
+ action_links: list[tuple[str, str]] | None = None,
):
payload = notification_broadcast_test_data()
if subject is not None:
@@ -428,7 +425,7 @@ class NotificationsIntegrationBase(IntegrationTestCase):
else:
assert response["total_notifications_sent"] == expected_count
- def _get_notification_id_by_subject(self, subject: str) -> Optional[str]:
+ def _get_notification_id_by_subject(self, subject: str) -> str | None:
notifications = self._get("notifications").json()
for notification in notifications:
if notification["content"]["subject"] == subject:
diff --git a/test/integration/test_prefix_handling.py b/test/integration/test_prefix_handling.py
index 705952f42fe..f2b65947017 100644
--- a/test/integration/test_prefix_handling.py
+++ b/test/integration/test_prefix_handling.py
@@ -34,5 +34,5 @@ class TestPrefixUrlSerializationIntegration(integration_util.IntegrationTestCase
# but it's a real pain to work with the reverse lookup in routes and the callback URLs
# do need to include the prefix.
assert href.startswith(f"{self.url_prefix}/display_application")
- response = self._get(f"{self.url[:-(len(self.url_prefix) + 1)]}{href}")
+ response = self._get(f"{self.url[: -(len(self.url_prefix) + 1)]}{href}")
response.raise_for_status()
diff --git a/test/integration/test_purge_datasets.py b/test/integration/test_purge_datasets.py
index 1a129da03aa..5f8d3255efa 100644
--- a/test/integration/test_purge_datasets.py
+++ b/test/integration/test_purge_datasets.py
@@ -1,8 +1,5 @@
import os
from collections.abc import Callable
-from typing import (
- Optional,
-)
from galaxy_test.base.populators import (
DatasetCollectionPopulator,
@@ -138,11 +135,11 @@ class TestPurgeDatasetsIntegration(integration_util.IntegrationTestCase):
)
assert details["deleted"]
- def _get_underlying_dataset_on_disk(self, hda_id: str) -> Optional[str]:
+ def _get_underlying_dataset_on_disk(self, hda_id: str) -> str | None:
detailed_response = self._get(f"datasets/{hda_id}", admin=True).json()
return detailed_response.get("file_name")
- def _file_exists_on_disk(self, filename: Optional[str]) -> bool:
+ def _file_exists_on_disk(self, filename: str | None) -> bool:
return os.path.isfile(filename) if filename else False
diff --git a/test/integration/test_storage_cleaner.py b/test/integration/test_storage_cleaner.py
index 19ebd681793..94536e15a2d 100644
--- a/test/integration/test_storage_cleaner.py
+++ b/test/integration/test_storage_cleaner.py
@@ -1,6 +1,5 @@
from typing import (
NamedTuple,
- Optional,
)
from uuid import uuid4
@@ -125,7 +124,7 @@ class TestStorageCleaner(integration_util.IntegrationTestCase):
resource: str,
test_items: list[StoredItemDataForTests],
item_ids: list[str],
- delete_resource_uri: Optional[str] = None,
+ delete_resource_uri: str | None = None,
):
"""Tests the storage cleaner API for a particular resource (histories or datasets)"""
delete_resource_uri = delete_resource_uri if delete_resource_uri else resource
diff --git a/test/integration/test_upload_configuration_options.py b/test/integration/test_upload_configuration_options.py
index b4ba06daab9..ec093274d51 100644
--- a/test/integration/test_upload_configuration_options.py
+++ b/test/integration/test_upload_configuration_options.py
@@ -992,7 +992,6 @@ class TestLinkDataUploadExtendedMetadata(BaseUploadContentConfigurationTestCase)
# but perfectly valid configurations for running metadata are not being tested by API
# tests anymore.
class TestUploadWithDirectoryMetadata(BaseUploadContentConfigurationTestCase):
-
@classmethod
def handle_galaxy_config_kwds(cls, config) -> None:
super().handle_galaxy_config_kwds(config)
@@ -1003,7 +1002,6 @@ class TestUploadWithDirectoryMetadata(BaseUploadContentConfigurationTestCase):
class TestUploadWithExtendedMetadata(BaseUploadContentConfigurationTestCase):
-
@classmethod
def handle_galaxy_config_kwds(cls, config) -> None:
super().handle_galaxy_config_kwds(config)
diff --git a/test/integration/test_user_defined_tool_job_conf.py b/test/integration/test_user_defined_tool_job_conf.py
index 19c5423c786..1fed96e4fcd 100644
--- a/test/integration/test_user_defined_tool_job_conf.py
+++ b/test/integration/test_user_defined_tool_job_conf.py
@@ -81,7 +81,6 @@ class TestUserDefinedToolRecommendedJobSetup(integration_util.IntegrationTestCas
class TestUserDefinedToolRecommendedJobSetupTPV(TestUserDefinedToolRecommendedJobSetup):
-
job_config_file = EMBEDDED_PULSAR_TPV_JOB_CONFIG_FILE
def test_user_defined_applies_resource_requirements(self):
diff --git a/test/integration/test_workflow_tasks.py b/test/integration/test_workflow_tasks.py
index cd141720c2b..bf0ffb05b49 100644
--- a/test/integration/test_workflow_tasks.py
+++ b/test/integration/test_workflow_tasks.py
@@ -382,26 +382,23 @@ steps:
# Test 2: Export with include_hidden=True, include_deleted=False
# Expected: 3 datasets (input_1 + output_1[hidden] + output_3)
dataset_files = self._export_and_get_datasets(invocation_id, include_hidden=True, include_deleted=False)
- assert len(dataset_files) == 3, (
- f"Test 2 (hidden=True, deleted=False): Expected 3 datasets, found {len(dataset_files)}: "
- f"{dataset_files}"
- )
+ assert (
+ len(dataset_files) == 3
+ ), f"Test 2 (hidden=True, deleted=False): Expected 3 datasets, found {len(dataset_files)}: {dataset_files}"
# Test 3: Export with include_hidden=False, include_deleted=True
# Expected: 3 datasets (input_1 + output_2[deleted] + output_3)
dataset_files = self._export_and_get_datasets(invocation_id, include_hidden=False, include_deleted=True)
- assert len(dataset_files) == 3, (
- f"Test 3 (hidden=False, deleted=True): Expected 3 datasets, found {len(dataset_files)}: "
- f"{dataset_files}"
- )
+ assert (
+ len(dataset_files) == 3
+ ), f"Test 3 (hidden=False, deleted=True): Expected 3 datasets, found {len(dataset_files)}: {dataset_files}"
# Test 4: Export with include_hidden=True, include_deleted=True
# Expected: 4 datasets (input_1 + output_1[hidden] + output_2[deleted] + output_3)
dataset_files = self._export_and_get_datasets(invocation_id, include_hidden=True, include_deleted=True)
- assert len(dataset_files) == 4, (
- f"Test 4 (hidden=True, deleted=True): Expected 4 datasets, found {len(dataset_files)}: "
- f"{dataset_files}"
- )
+ assert (
+ len(dataset_files) == 4
+ ), f"Test 4 (hidden=True, deleted=True): Expected 4 datasets, found {len(dataset_files)}: {dataset_files}"
def _export_and_get_datasets(self, invocation_id: str, include_hidden: bool, include_deleted: bool) -> list[str]:
"""Helper method to export an invocation and return the list of dataset files in the archive."""
diff --git a/test/integration_selenium/test_user_file_source_azure.py b/test/integration_selenium/test_user_file_source_azure.py
index cb0f1a86cb5..843ba6cb12a 100644
--- a/test/integration_selenium/test_user_file_source_azure.py
+++ b/test/integration_selenium/test_user_file_source_azure.py
@@ -13,7 +13,6 @@ from .framework import (
class TestObjectStoreSelectionSeleniumIntegration(BaseUserObjectStoreSeleniumIntegration):
-
@skip_unless_environ("GALAXY_TEST_AZURE_CONTAINER_NAME")
@skip_unless_environ("GALAXY_TEST_AZURE_ACCOUNT_KEY")
@skip_unless_environ("GALAXY_TEST_AZURE_ACCOUNT_NAME")
diff --git a/test/unit/app/jobs/test_job_configuration.py b/test/unit/app/jobs/test_job_configuration.py
index aa0466ae927..0adebb5ec5f 100644
--- a/test/unit/app/jobs/test_job_configuration.py
+++ b/test/unit/app/jobs/test_job_configuration.py
@@ -2,9 +2,6 @@ import datetime
import os
import shutil
import tempfile
-from typing import (
- Optional,
-)
from unittest import mock
from pykwalify.core import Core
@@ -98,7 +95,7 @@ class BaseJobConfXmlParserTestCase(TestCase):
self._job_configuration_base_pools = base_pools
self._write_config_from(HANDLER_TEMPLATE_JOB_CONF, template=template)
- def _write_config_from(self, path: StrPath, template: Optional[dict[str, str]] = None) -> None:
+ def _write_config_from(self, path: StrPath, template: dict[str, str] | None = None) -> None:
template = template or {}
try:
contents = open(path).read()
diff --git a/test/unit/app/jobs/test_job_wrapper.py b/test/unit/app/jobs/test_job_wrapper.py
index 2de5f65062b..8005235d310 100644
--- a/test/unit/app/jobs/test_job_wrapper.py
+++ b/test/unit/app/jobs/test_job_wrapper.py
@@ -69,7 +69,9 @@ class AbstractTestCases:
@contextmanager
def _prepared_wrapper(self):
wrapper = self._wrapper()
- wrapper._get_tool_evaluator = lambda *args, **kwargs: MockEvaluator(wrapper.app, wrapper.tool, wrapper.get_job(), wrapper.working_directory) # type: ignore[method-assign]
+ wrapper._get_tool_evaluator = lambda *args, **kwargs: MockEvaluator( # type: ignore[method-assign]
+ wrapper.app, wrapper.tool, wrapper.get_job(), wrapper.working_directory
+ )
wrapper.prepare()
yield wrapper
diff --git a/test/unit/app/jobs/test_queue_limit.py b/test/unit/app/jobs/test_queue_limit.py
index b3defe4bed7..5441ab7cd95 100644
--- a/test/unit/app/jobs/test_queue_limit.py
+++ b/test/unit/app/jobs/test_queue_limit.py
@@ -1,4 +1,3 @@
-from typing import Optional
from unittest.mock import Mock
from galaxy.jobs import (
@@ -14,7 +13,6 @@ from galaxy.model.unittest_utils.data_app import GalaxyDataTestConfig
class MockJobConfig:
-
def __init__(self) -> None:
self.limits = JobConfigurationLimits()
@@ -23,8 +21,7 @@ class MockJobConfig:
class GalaxyJobConfigApp(GalaxyDataTestApp):
-
- def __init__(self, config: Optional[GalaxyDataTestConfig] = None, **kwd):
+ def __init__(self, config: GalaxyDataTestConfig | None = None, **kwd):
super().__init__(config, **kwd)
self.job_config = MockJobConfig()
diff --git a/test/unit/app/jobs/test_runner_local.py b/test/unit/app/jobs/test_runner_local.py
index 8db31b5f6f2..82fbc889109 100644
--- a/test/unit/app/jobs/test_runner_local.py
+++ b/test/unit/app/jobs/test_runner_local.py
@@ -4,7 +4,6 @@ import threading
import time
from typing import (
cast,
- Optional,
TYPE_CHECKING,
)
@@ -179,7 +178,7 @@ class MockJobWrapper:
self.remote_command_line = False
# Cruft for setting metadata externally, axe at some point.
- self.external_output_metadata: Optional[bunch.Bunch] = bunch.Bunch()
+ self.external_output_metadata: bunch.Bunch | None = bunch.Bunch()
self.app.datatypes_registry.set_external_metadata_tool = bunch.Bunch(build_dependency_shell_commands=lambda: [])
def check_tool_output(*args, **kwds):
diff --git a/test/unit/app/managers/test_CredentialsManager.py b/test/unit/app/managers/test_CredentialsManager.py
index 2d575ba8a9d..721660f950a 100644
--- a/test/unit/app/managers/test_CredentialsManager.py
+++ b/test/unit/app/managers/test_CredentialsManager.py
@@ -8,7 +8,6 @@ from .base import BaseTestCase
class TestCredentialsManager(BaseTestCase):
-
def set_up_managers(self):
super().set_up_managers()
self.credentials_manager = CredentialsManager(self.trans.sa_session)
diff --git a/test/unit/app/managers/test_HDAManager.py b/test/unit/app/managers/test_HDAManager.py
index 31c22894b00..a2997f4f6a7 100644
--- a/test/unit/app/managers/test_HDAManager.py
+++ b/test/unit/app/managers/test_HDAManager.py
@@ -231,8 +231,7 @@ class TestHDAManager(HDATestCase):
)
self.log(
- "a copy of a restricted dataset in another users history should be inaccessible even to "
- "the histories owner"
+ "a copy of a restricted dataset in another users history should be inaccessible even to the histories owner"
)
history2 = self.history_manager.create(name="history2", user=non_owner)
self.trans.set_history(history2)
diff --git a/test/unit/app/managers/test_NotificationManager.py b/test/unit/app/managers/test_NotificationManager.py
index eb582421221..26148d707a9 100644
--- a/test/unit/app/managers/test_NotificationManager.py
+++ b/test/unit/app/managers/test_NotificationManager.py
@@ -5,7 +5,6 @@ from datetime import (
from typing import (
Any,
cast,
- Optional,
)
from unittest.mock import (
MagicMock,
@@ -78,7 +77,7 @@ class NotificationManagerBaseTestCase(NotificationsBaseTestCase):
},
}
- def _send_message_notification_to_users(self, users: list[User], notification: Optional[dict[str, Any]] = None):
+ def _send_message_notification_to_users(self, users: list[User], notification: dict[str, Any] | None = None):
data = self._default_test_notification_data()
if notification:
data.update(notification)
@@ -94,7 +93,7 @@ class NotificationManagerBaseTestCase(NotificationsBaseTestCase):
created_notification, notifications_sent = self.notification_manager.send_notification_to_recipients(request)
return created_notification, notifications_sent
- def _has_expired(self, expiration_time: Optional[datetime]) -> bool:
+ def _has_expired(self, expiration_time: datetime | None) -> bool:
return expiration_time < now() if expiration_time else False
def _assert_notification_expected(self, actual_notification: Any, expected_notification: dict[str, Any]):
@@ -459,7 +458,6 @@ class TestUserNotifications(NotificationManagerBaseTestCase):
class TestUserNotificationsWithTasks(NotificationManagerBaseTestCaseWithTasks):
-
def test_urgent_notifications_via_email_channel(self):
user = self._create_test_user()
# Disable email channel only
diff --git a/test/unit/app/managers/test_headers_encryption.py b/test/unit/app/managers/test_headers_encryption.py
index 5bf5cbeb45c..f780a185d9f 100644
--- a/test/unit/app/managers/test_headers_encryption.py
+++ b/test/unit/app/managers/test_headers_encryption.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
import pytest
from galaxy.config.url_headers import UrlHeadersConfigFactory
@@ -26,7 +24,7 @@ class MockVault(Vault):
def write_secret(self, key: str, value: str) -> None:
self.storage[key] = value
- def read_secret(self, key: str) -> Optional[str]:
+ def read_secret(self, key: str) -> str | None:
return self.storage.get(key)
def list_secrets(self, key: str) -> list[str]:
diff --git a/test/unit/app/managers/test_landing.py b/test/unit/app/managers/test_landing.py
index 33a30eb424c..aa12e08390b 100644
--- a/test/unit/app/managers/test_landing.py
+++ b/test/unit/app/managers/test_landing.py
@@ -45,20 +45,17 @@ CLIENT_SECRET = "mycoolsecret"
class MockApp:
-
@property
def toolbox(self):
return MockToolbox()
class MockToolbox:
-
def get_tool(self, tool_id, tool_uuid, tool_version, user):
return MockTool()
class MockTool:
-
id = TEST_TOOL_ID
@property
@@ -67,7 +64,6 @@ class MockTool:
class TestLanding(BaseTestCase):
-
def setUp(self):
super().setUp()
self.workflow_contents_manager = WorkflowContentsManager(self.app, self.app.trs_proxy)
diff --git a/test/unit/app/managers/test_queue_metrics.py b/test/unit/app/managers/test_queue_metrics.py
index 8ef9aa65998..8cdcb36914f 100644
--- a/test/unit/app/managers/test_queue_metrics.py
+++ b/test/unit/app/managers/test_queue_metrics.py
@@ -18,7 +18,6 @@ from dataclasses import (
from types import SimpleNamespace
from typing import (
cast,
- Optional,
)
from unittest.mock import MagicMock
@@ -41,14 +40,14 @@ class FakeStatsdClient:
counters: dict[tuple[str, tuple[tuple[str, str], ...]], int] = field(default_factory=dict)
gauges: list[tuple[str, float, tuple[tuple[str, str], ...]]] = field(default_factory=list)
- def incr(self, metric: str, tags: Optional[dict[str, str]] = None) -> None:
+ def incr(self, metric: str, tags: dict[str, str] | None = None) -> None:
key = (metric, tuple(sorted((tags or {}).items())))
self.counters[key] = self.counters.get(key, 0) + 1
- def gauge(self, metric: str, value: float, tags: Optional[dict[str, str]] = None) -> None:
+ def gauge(self, metric: str, value: float, tags: dict[str, str] | None = None) -> None:
self.gauges.append((metric, value, tuple(sorted((tags or {}).items()))))
- def counter(self, metric: str, tags: Optional[dict[str, str]] = None) -> int:
+ def counter(self, metric: str, tags: dict[str, str] | None = None) -> int:
return self.counters.get((metric, tuple(sorted((tags or {}).items()))), 0)
def gauges_for(self, metric: str) -> list[tuple[float, dict[str, str]]]:
diff --git a/test/unit/app/managers/test_sse_connection_gauges.py b/test/unit/app/managers/test_sse_connection_gauges.py
index c3f09bb0553..ff3e8396113 100644
--- a/test/unit/app/managers/test_sse_connection_gauges.py
+++ b/test/unit/app/managers/test_sse_connection_gauges.py
@@ -15,7 +15,6 @@ from dataclasses import (
)
from typing import (
cast,
- Optional,
)
from galaxy.managers.sse import (
@@ -36,7 +35,7 @@ class FakeStatsdClient:
gauges: list[tuple[str, float, tuple[tuple[str, str], ...]]] = field(default_factory=list)
recorded: threading.Event = field(default_factory=threading.Event)
- def gauge(self, metric: str, value: float, tags: Optional[dict[str, str]] = None) -> None:
+ def gauge(self, metric: str, value: float, tags: dict[str, str] | None = None) -> None:
self.gauges.append((metric, value, tuple(sorted((tags or {}).items()))))
self.recorded.set()
@@ -44,8 +43,8 @@ class FakeStatsdClient:
return [(v, dict(t)) for m, v, t in self.gauges if m == metric]
-def _manager(statsd: Optional[FakeStatsdClient]) -> SSEConnectionManager:
- return SSEConnectionManager(statsd_client=cast(Optional[VanillaGalaxyStatsdClient], statsd))
+def _manager(statsd: FakeStatsdClient | None) -> SSEConnectionManager:
+ return SSEConnectionManager(statsd_client=cast(VanillaGalaxyStatsdClient | None, statsd))
async def test_emit_connection_gauges_reports_own_counts_tagged_by_server_name():
diff --git a/test/unit/app/managers/test_sse_dispatch.py b/test/unit/app/managers/test_sse_dispatch.py
index 2118ccacdc0..494497b28cf 100644
--- a/test/unit/app/managers/test_sse_dispatch.py
+++ b/test/unit/app/managers/test_sse_dispatch.py
@@ -17,7 +17,6 @@ from dataclasses import (
)
from typing import (
Any,
- Optional,
)
from unittest.mock import MagicMock
@@ -38,14 +37,14 @@ class FakeStatsdClient:
counters: dict[tuple[str, tuple[tuple[str, str], ...]], int] = field(default_factory=dict)
timings: list[tuple[str, float, tuple[tuple[str, str], ...]]] = field(default_factory=list)
- def incr(self, metric: str, tags: Optional[dict[str, str]] = None) -> None:
+ def incr(self, metric: str, tags: dict[str, str] | None = None) -> None:
key = (metric, tuple(sorted((tags or {}).items())))
self.counters[key] = self.counters.get(key, 0) + 1
- def timing(self, metric: str, value: float, tags: Optional[dict[str, str]] = None) -> None:
+ def timing(self, metric: str, value: float, tags: dict[str, str] | None = None) -> None:
self.timings.append((metric, value, tuple(sorted((tags or {}).items()))))
- def counter(self, metric: str, tags: Optional[dict[str, str]] = None) -> int:
+ def counter(self, metric: str, tags: dict[str, str] | None = None) -> int:
return self.counters.get((metric, tuple(sorted((tags or {}).items()))), 0)
@@ -53,7 +52,7 @@ class FakeStatsdClient:
class RecordedTask:
payload: dict[str, Any]
routing_key: str
- expiration: Optional[int]
+ expiration: int | None
declare_queues: Any
@@ -71,7 +70,7 @@ class FakeControlTask:
self,
payload: dict[str, Any],
routing_key: str,
- expiration: Optional[int] = None,
+ expiration: int | None = None,
declare_queues: Any = None,
**_: Any,
) -> None:
diff --git a/test/unit/app/managers/test_user_file_sources.py b/test/unit/app/managers/test_user_file_sources.py
index b9a2c04e57c..848f1c72c9c 100644
--- a/test/unit/app/managers/test_user_file_sources.py
+++ b/test/unit/app/managers/test_user_file_sources.py
@@ -1,7 +1,6 @@
import os
from typing import (
cast,
- Optional,
)
from uuid import uuid4
@@ -53,8 +52,8 @@ SIMPLE_FILE_SOURCE_DESCRIPTION = "a description of my file source"
class Config:
- file_source_templates: Optional[list[RawTemplateConfig]] = None
- file_source_templates_config_file: Optional[str] = None
+ file_source_templates: list[RawTemplateConfig] | None = None
+ file_source_templates_config_file: str | None = None
def __init__(self, templates: list[RawTemplateConfig]):
self.file_source_templates = templates
@@ -309,7 +308,6 @@ class TestFileSourcesTestCase(BaseTestCase):
fsspec_fs_init_kwd = {}
class MockDropboxDriveFileSystem:
-
def __init__(self, **kwd):
fsspec_fs_init_kwd.update(kwd)
@@ -1042,7 +1040,6 @@ class MockResponse:
class MockExceptionResponse:
-
def __init__(self, exception_msg: str):
self._exception_msg = exception_msg
@@ -1051,7 +1048,6 @@ class MockExceptionResponse:
class OneDriveMockResponse:
-
def __init__(self, status_code=200, json_data=None, text=""):
self.status_code = status_code
self._json_data = json_data or {}
diff --git a/test/unit/app/managers/test_user_object_stores.py b/test/unit/app/managers/test_user_object_stores.py
index 111a515cc09..eec76e86b40 100644
--- a/test/unit/app/managers/test_user_object_stores.py
+++ b/test/unit/app/managers/test_user_object_stores.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from yaml import safe_load
from galaxy.exceptions import (
@@ -29,8 +27,8 @@ SIMPLE_FILE_SOURCE_DESCRIPTION = "a description of my object store"
class Config:
- object_store_templates: Optional[list[RawTemplateConfig]] = None
- object_store_templates_config_file: Optional[str] = None
+ object_store_templates: list[RawTemplateConfig] | None = None
+ object_store_templates_config_file: str | None = None
def __init__(self, templates: list[RawTemplateConfig]):
self.object_store_templates = templates
diff --git a/test/unit/app/queue_worker/conftest.py b/test/unit/app/queue_worker/conftest.py
index 8c7846440cc..319dd7172a1 100644
--- a/test/unit/app/queue_worker/conftest.py
+++ b/test/unit/app/queue_worker/conftest.py
@@ -1,6 +1,5 @@
import os
import tempfile
-from typing import Optional
import pytest
@@ -12,7 +11,7 @@ except ImportError:
from galaxy.app_unittest_utils import galaxy_mock
-def create_base_test(connection, amqp_type: str, amqp_connection: Optional[str] = None):
+def create_base_test(connection, amqp_type: str, amqp_connection: str | None = None):
app = galaxy_mock.MockApp(database_connection=connection)
app.config.database_connection = connection
app.config.amqp_internal_connection = amqp_connection or f"sqlalchemy+{app.config.database_connection}"
diff --git a/test/unit/app/queue_worker/test_queue_worker.py b/test/unit/app/queue_worker/test_queue_worker.py
index 857bdeb2cac..f323e20fbbe 100644
--- a/test/unit/app/queue_worker/test_queue_worker.py
+++ b/test/unit/app/queue_worker/test_queue_worker.py
@@ -6,7 +6,6 @@ from dataclasses import (
)
from math import inf
from types import SimpleNamespace
-from typing import Optional
from unittest.mock import MagicMock
import pytest
@@ -28,14 +27,14 @@ class FakeStatsdClient:
counters: dict[tuple[str, tuple[tuple[str, str], ...]], int] = field(default_factory=dict)
timings: list[tuple[str, float, tuple[tuple[str, str], ...]]] = field(default_factory=list)
- def incr(self, metric: str, tags: Optional[dict[str, str]] = None) -> None:
+ def incr(self, metric: str, tags: dict[str, str] | None = None) -> None:
key = (metric, tuple(sorted((tags or {}).items())))
self.counters[key] = self.counters.get(key, 0) + 1
- def timing(self, metric: str, value: float, tags: Optional[dict[str, str]] = None) -> None:
+ def timing(self, metric: str, value: float, tags: dict[str, str] | None = None) -> None:
self.timings.append((metric, value, tuple(sorted((tags or {}).items()))))
- def counter(self, metric: str, tags: Optional[dict[str, str]] = None) -> int:
+ def counter(self, metric: str, tags: dict[str, str] | None = None) -> int:
return self.counters.get((metric, tuple(sorted((tags or {}).items()))), 0)
def timings_for(self, metric: str) -> list[tuple[float, dict[str, str]]]:
diff --git a/test/unit/app/test_dbscript.py b/test/unit/app/test_dbscript.py
index 11ef77d27f4..76d3b6527b7 100644
--- a/test/unit/app/test_dbscript.py
+++ b/test/unit/app/test_dbscript.py
@@ -59,7 +59,12 @@ def alembic_env_dir(migrations_dir: Traversable) -> Traversable:
@pytest.fixture(params=["one database", "two databases"])
def config(
- url_factory, alembic_env_dir: Traversable, alembic_config_text, tmp_directory, monkeypatch, request # noqa: F811
+ url_factory, # noqa: F811
+ alembic_env_dir: Traversable,
+ alembic_config_text, # noqa: F811
+ tmp_directory, # noqa: F811
+ monkeypatch,
+ request,
):
"""
Construct Config object for staging; setup staging env.
diff --git a/test/unit/app/test_markdown_validate.py b/test/unit/app/test_markdown_validate.py
index 2694a37de5a..603f3a9a112 100644
--- a/test/unit/app/test_markdown_validate.py
+++ b/test/unit/app/test_markdown_validate.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from galaxy.managers.markdown_parse import validate_galaxy_markdown
@@ -7,7 +5,7 @@ def assert_markdown_valid(markdown):
validate_galaxy_markdown(markdown)
-def assert_markdown_invalid(markdown, at_line: Optional[int] = None):
+def assert_markdown_invalid(markdown, at_line: int | None = None):
failed = False
try:
validate_galaxy_markdown(markdown)
diff --git a/test/unit/app/tools/test_actions.py b/test/unit/app/tools/test_actions.py
index d6ec06b4412..89d6a7dfa71 100644
--- a/test/unit/app/tools/test_actions.py
+++ b/test/unit/app/tools/test_actions.py
@@ -1,7 +1,6 @@
import string
from typing import (
cast,
- Optional,
)
from galaxy import model
@@ -285,9 +284,7 @@ def __assert_output_format_is(expected, output, input_extensions=None, param_con
assert actual_format == expected, f"Actual format {actual_format}, does not match expected {expected}"
-def quick_output(
- format: str, format_source: Optional[str] = None, change_format_xml: Optional[str] = None
-) -> ToolOutput:
+def quick_output(format: str, format_source: str | None = None, change_format_xml: str | None = None) -> ToolOutput:
test_output = ToolOutput("test_output")
test_output.format = format
test_output.format_source = format_source
diff --git a/test/unit/app/tools/test_data_fetch.py b/test/unit/app/tools/test_data_fetch.py
index 61e776a106a..81d0a28e3ab 100644
--- a/test/unit/app/tools/test_data_fetch.py
+++ b/test/unit/app/tools/test_data_fetch.py
@@ -5,7 +5,6 @@ from base64 import b64encode
from contextlib import contextmanager
from shutil import rmtree
from tempfile import mkdtemp
-from typing import Optional
import pytest
@@ -25,7 +24,7 @@ URI_FOR_1_2_3 = f"base64://{B64_FOR_1_2_3}"
),
],
)
-def test_simple_path_get(hash_value: str, error_message: Optional[str]):
+def test_simple_path_get(hash_value: str, error_message: str | None):
with _execute_context() as execute_context:
job_directory = execute_context.job_directory
example_path = os.path.join(job_directory, "example_file")
diff --git a/test/unit/app/tools/test_data_parameters.py b/test/unit/app/tools/test_data_parameters.py
index 42d4a1d089c..5b39d5b2b70 100644
--- a/test/unit/app/tools/test_data_parameters.py
+++ b/test/unit/app/tools/test_data_parameters.py
@@ -1,6 +1,5 @@
from typing import (
Any,
- Optional,
)
import pytest
@@ -237,7 +236,7 @@ class MockHistoryDatasetAssociation:
self.deleted = False
self.dataset = test_dataset
self.visible = True
- self.conversion_destination: tuple[bool, Optional[str], Optional[Any]] = (True, None, None)
+ self.conversion_destination: tuple[bool, str | None, Any | None] = (True, None, None)
self.extension = "txt"
self.dbkey = "hg19"
self.implicitly_converted_parent_datasets = False
diff --git a/test/unit/app/tools/test_empy_datasets_tool.py b/test/unit/app/tools/test_empy_datasets_tool.py
index ab259b73e60..cc00af7bca5 100644
--- a/test/unit/app/tools/test_empy_datasets_tool.py
+++ b/test/unit/app/tools/test_empy_datasets_tool.py
@@ -1,7 +1,6 @@
import gzip
import tempfile
from contextlib import contextmanager
-from typing import Union
from galaxy.model import (
Dataset,
@@ -15,7 +14,7 @@ from galaxy.tools import FilterEmptyDatasetsTool
def get_dce(empty, compressed):
dataset = Dataset()
with tempfile.NamedTemporaryFile(mode="wb") as out:
- fh: Union[gzip.GzipFile, tempfile._TemporaryFileWrapper]
+ fh: gzip.GzipFile | tempfile._TemporaryFileWrapper
if compressed:
fh = gzip.open(out.name, "wb")
else:
diff --git a/test/unit/app/tools/test_error_reporting.py b/test/unit/app/tools/test_error_reporting.py
index f9c18c41eb5..4b81218de15 100644
--- a/test/unit/app/tools/test_error_reporting.py
+++ b/test/unit/app/tools/test_error_reporting.py
@@ -20,7 +20,6 @@ TEST_SERVER_ERROR_EMAIL_TO = "admin@email.to" # setup in mock config
class TestErrorReporter(TestCase, UsesApp):
-
def setUp(self):
self.setup_app()
self.app.config.email_from = TEST_SERVER_EMAIL_FROM
diff --git a/test/unit/app/tools/test_select_parameters.py b/test/unit/app/tools/test_select_parameters.py
index a4587691152..6c9fcaa38f1 100644
--- a/test/unit/app/tools/test_select_parameters.py
+++ b/test/unit/app/tools/test_select_parameters.py
@@ -9,7 +9,6 @@ from .util import BaseParameterTestCase
class TestSelectToolParameter(BaseParameterTestCase):
-
def new_hda(self):
hda = model.HistoryDatasetAssociation()
hda._state = model.Dataset.states.OK
diff --git a/test/unit/app/tools/test_toolbox.py b/test/unit/app/tools/test_toolbox.py
index 3d01190338c..96f672c0786 100644
--- a/test/unit/app/tools/test_toolbox.py
+++ b/test/unit/app/tools/test_toolbox.py
@@ -1,7 +1,6 @@
import logging
import time
from typing import (
- Optional,
TYPE_CHECKING,
)
from unittest.mock import MagicMock
@@ -261,7 +260,7 @@ class TestToolBox(BaseToolBoxTestCase):
return user
def _persist_dynamic_tool(
- self, public: bool, active: bool = True, owner: Optional[model.User] = None
+ self, public: bool, active: bool = True, owner: model.User | None = None
) -> model.DynamicTool:
session = self.app.model.context
dyn = model.DynamicTool(
diff --git a/test/unit/app/tools/test_validation_parsing.py b/test/unit/app/tools/test_validation_parsing.py
index c13b0973e6a..701649d491e 100644
--- a/test/unit/app/tools/test_validation_parsing.py
+++ b/test/unit/app/tools/test_validation_parsing.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from galaxy.tool_util.unittest_utils.sample_data import (
INVALID_XML_VALIDATORS,
VALID_XML_VALIDATORS,
@@ -9,14 +7,12 @@ from galaxy.util import XML
class MockApp:
-
@property
def tool_data_tables(self):
return {"mycooltable": MockTable()}
class MockTable:
-
def get_version_fields(self):
return (1, [])
@@ -28,7 +24,7 @@ def test_xml_validation_valid():
def test_xml_validation_invalid():
for xml_validator in INVALID_XML_VALIDATORS:
- exc: Optional[Exception] = None
+ exc: Exception | None = None
try:
_validate_xml_str(xml_validator)
except ValueError as e:
diff --git a/test/unit/app/visualizations/plugins/test_VisualizationPlugin.py b/test/unit/app/visualizations/plugins/test_VisualizationPlugin.py
index a8bb2680757..403c7efc275 100644
--- a/test/unit/app/visualizations/plugins/test_VisualizationPlugin.py
+++ b/test/unit/app/visualizations/plugins/test_VisualizationPlugin.py
@@ -8,7 +8,6 @@ from . import VisualizationsBase_TestCase
class TestVisualizationsPlugin(VisualizationsBase_TestCase):
-
def test_default_init(self):
"""
A plugin with no context passed in should have sane defaults.
diff --git a/test/unit/authnz/test_authnz.py b/test/unit/authnz/test_authnz.py
index 9d17188df0f..91a8b3599f8 100644
--- a/test/unit/authnz/test_authnz.py
+++ b/test/unit/authnz/test_authnz.py
@@ -2,7 +2,6 @@ import tempfile
from typing import (
Any,
cast,
- Optional,
)
from unittest.mock import (
MagicMock,
@@ -123,7 +122,7 @@ class AuthenticatedStubGalaxyWebTransaction(StubGalaxyWebTransaction):
self.user = self.auth_user
self.galaxy_session = None
- def _authenticate_api(self, session_cookie: str) -> Optional[str]:
+ def _authenticate_api(self, session_cookie: str) -> str | None:
self.user = self.auth_user
self.galaxy_session = None
return None
@@ -233,7 +232,7 @@ def test_psa_authnz_config(mock_app):
assert psa_authnz.config[setting_name("USERNAME_KEY")] == config_values["username_key"]
-def _create_backend_config_with_idphint(idphint_value: Optional[str] = None) -> tuple[str, str]:
+def _create_backend_config_with_idphint(idphint_value: str | None = None) -> tuple[str, str]:
"""Create a Keycloak backend config, optionally including an element."""
idphint_element = f" {idphint_value} " if idphint_value else ""
contents = f"""
diff --git a/test/unit/authnz/test_psa_authnz.py b/test/unit/authnz/test_psa_authnz.py
index ca59055ed43..e5fb3da3a14 100644
--- a/test/unit/authnz/test_psa_authnz.py
+++ b/test/unit/authnz/test_psa_authnz.py
@@ -8,7 +8,6 @@ from datetime import (
timedelta,
)
from types import SimpleNamespace
-from typing import Optional
from unittest.mock import (
MagicMock,
patch,
@@ -107,15 +106,15 @@ class AuthTokenData:
def create_access_token(
email: str = "user@example.com",
- roles: Optional[list[str]] = None,
+ roles: list[str] | None = None,
iss: str = "https://issuer.example.com",
- sub: Optional[str] = None,
- iat: Optional[int] = None,
- exp: Optional[int] = None,
+ sub: str | None = None,
+ iat: int | None = None,
+ exp: int | None = None,
aud: str = "https://audience.example.com",
- scope: Optional[list[str]] = None,
- azp: Optional[str] = None,
- permissions: Optional[list[str]] = None,
+ scope: list[str] | None = None,
+ azp: str | None = None,
+ permissions: list[str] | None = None,
algorithm: str = "RS256",
public_key_id: str = "example-key",
) -> AuthTokenData:
diff --git a/test/unit/data/datatypes/test_qiime2.py b/test/unit/data/datatypes/test_qiime2.py
index aa8948f5bed..501935da82c 100644
--- a/test/unit/data/datatypes/test_qiime2.py
+++ b/test/unit/data/datatypes/test_qiime2.py
@@ -160,8 +160,7 @@ def test_strip_properties_nested():
def test_strip_properties_complex():
complex_expression = (
- 'Tuple[FeatureData[Taxonomy % Properties("SILVA")] % Axis("ASV")'
- ', DistanceMatrix % Axes("ASV", "ASV")] % Unique'
+ 'Tuple[FeatureData[Taxonomy % Properties("SILVA")] % Axis("ASV"), DistanceMatrix % Axes("ASV", "ASV")] % Unique'
)
stripped_expression = "Tuple[FeatureData[Taxonomy], DistanceMatrix]"
diff --git a/test/unit/data/datatypes/util.py b/test/unit/data/datatypes/util.py
index 01b496435b5..667f814609a 100644
--- a/test/unit/data/datatypes/util.py
+++ b/test/unit/data/datatypes/util.py
@@ -2,7 +2,6 @@ import os
import shutil
import tempfile
from contextlib import contextmanager
-from typing import Optional
from galaxy.datatypes.sniff import get_test_fname
from galaxy.util.bunch import Bunch
@@ -22,7 +21,7 @@ class MockDatasetDataset:
class MockMetadata(Bunch):
- file_name_: Optional[str] = None
+ file_name_: str | None = None
def get_file_name(self, sync_cache=True):
return self.file_name_
@@ -36,7 +35,7 @@ class MockDataset:
self.id = id
self.metadata = MockMetadata()
self.dataset = None
- self.file_name_: Optional[str] = None
+ self.file_name_: str | None = None
def get_file_name(self, sync_cache=True):
return self.file_name_
diff --git a/test/unit/data/model/__init__.py b/test/unit/data/model/__init__.py
index 7d0a1eeb1f8..5570878a767 100644
--- a/test/unit/data/model/__init__.py
+++ b/test/unit/data/model/__init__.py
@@ -2,7 +2,6 @@ PRIVATE_OBJECT_STORE_ID = "my_private_data"
class MockObjectStore:
-
def is_private(self, object):
if object.object_store_id == PRIVATE_OBJECT_STORE_ID:
return True
diff --git a/test/unit/data/model/db/test_security.py b/test/unit/data/model/db/test_security.py
index a255e408048..e8c03362c3d 100644
--- a/test/unit/data/model/db/test_security.py
+++ b/test/unit/data/model/db/test_security.py
@@ -72,7 +72,6 @@ def test_get_sharing_roles(session, make_user):
class TestSetGroupUserAndRoleAssociations:
-
def test_add_associations_to_existing_group(self, session, make_user_and_role, make_role, make_group):
"""
State: group exists in database, has no user and role associations.
diff --git a/test/unit/data/model/migrations/test_migrations.py b/test/unit/data/model/migrations/test_migrations.py
index 832b4c50488..64bac39a7e2 100644
--- a/test/unit/data/model/migrations/test_migrations.py
+++ b/test/unit/data/model/migrations/test_migrations.py
@@ -1,5 +1,4 @@
import os
-from typing import Union
import alembic
import pytest
@@ -1031,7 +1030,7 @@ def _setup_db_state4(db_url, metadata, last_version, model=None):
load_metadata(metadata, engine)
load_sqlalchemymigrate_version(db_url, last_version)
- revisions: Union[str, list]
+ revisions: str | list
if model == GXY:
revisions = GXY_REVISION_0
elif model == TSI:
@@ -1065,7 +1064,7 @@ def _setup_db_state5(db_url, metadata, model=None):
with disposing_engine(db_url) as engine:
load_metadata(metadata, engine)
- revisions: Union[str, list]
+ revisions: str | list
if model == GXY:
revisions = GXY_REVISION_1
elif model == TSI:
@@ -1099,7 +1098,7 @@ def _setup_db_state6(db_url, metadata, model=None):
with disposing_engine(db_url) as engine:
load_metadata(metadata, engine)
- revisions: Union[str, list]
+ revisions: str | list
if model == GXY:
revisions = GXY_REVISION_2
elif model == TSI:
diff --git a/test/unit/data/model/test_model_store.py b/test/unit/data/model/test_model_store.py
index 75128667f10..21722355fd9 100644
--- a/test/unit/data/model/test_model_store.py
+++ b/test/unit/data/model/test_model_store.py
@@ -12,7 +12,6 @@ from tempfile import (
from typing import (
Any,
NamedTuple,
- Optional,
)
import pytest
@@ -1445,7 +1444,7 @@ def setup_fixture_context_with_history(
def perform_import_from_store_dict(
fixture_context: StoreFixtureContextWithHistory,
import_dict: dict[str, Any],
- import_options: Optional[store.ImportOptions] = None,
+ import_options: store.ImportOptions | None = None,
) -> None:
import_options = import_options or store.ImportOptions()
import_model_store = store.get_import_model_store_for_dict(
diff --git a/test/unit/data/security/test_validate_user_input.py b/test/unit/data/security/test_validate_user_input.py
index 3b46595bcd7..ad5ff043e8e 100644
--- a/test/unit/data/security/test_validate_user_input.py
+++ b/test/unit/data/security/test_validate_user_input.py
@@ -59,7 +59,6 @@ def test_validate_email_str():
class TestIsEmailBanned:
-
mock_ban_list = ["ab@foo.com", "ab@gmail.com", "Not.Canonical+email+gmail+address@gmail.com"]
def test_default_canonical_rules(self, monkeypatch, appconfig):
diff --git a/test/unit/data/test_galaxy_mapping.py b/test/unit/data/test_galaxy_mapping.py
index 773ee74d5d8..6c7f8e6bacc 100644
--- a/test/unit/data/test_galaxy_mapping.py
+++ b/test/unit/data/test_galaxy_mapping.py
@@ -74,7 +74,6 @@ class BaseModelTestCase(TestCase):
class TestMappings(BaseModelTestCase):
-
def test_dataset_instance_order(self) -> None:
u = model.User(email=random_email(), password="password")
h1 = model.History(name="History 1", user=u)
diff --git a/test/unit/data/test_model_copy.py b/test/unit/data/test_model_copy.py
index ab795174675..a8e2b47af43 100644
--- a/test/unit/data/test_model_copy.py
+++ b/test/unit/data/test_model_copy.py
@@ -1,7 +1,6 @@
import contextlib
import os
import threading
-from typing import Union
from sqlalchemy.orm.scoping import scoped_session
@@ -150,7 +149,7 @@ def _setup_mapping_and_user():
def _create_hda(
- has_session: Union[mapping.GalaxyModelMapping, scoped_session],
+ has_session: mapping.GalaxyModelMapping | scoped_session,
object_store,
history,
path,
diff --git a/test/unit/files/_base.py b/test/unit/files/_base.py
index 13336570382..22b02d5851a 100644
--- a/test/unit/files/_base.py
+++ b/test/unit/files/_base.py
@@ -17,7 +17,6 @@ from abc import (
from collections.abc import Callable
from typing import (
Any,
- Optional,
)
import pytest
@@ -134,7 +133,7 @@ class BaseFileSourceTestSuite(ABC):
self._upload_content_to_path(file_source, path, content, user_context)
def _upload_content_to_path(
- self, file_source: BaseFilesSource, target_path: str, content: str, user_context: Optional[Any] = None
+ self, file_source: BaseFilesSource, target_path: str, content: str, user_context: Any | None = None
) -> None:
"""Helper method to upload content to a specific path in the file source."""
with tempfile.NamedTemporaryFile(mode="w") as temp_file:
diff --git a/test/unit/files/_util.py b/test/unit/files/_util.py
index d7103df5aae..a0dd2eea622 100644
--- a/test/unit/files/_util.py
+++ b/test/unit/files/_util.py
@@ -2,7 +2,6 @@
import os
import tempfile
-from typing import Optional
from galaxy.files import (
ConfiguredFileSources,
@@ -24,11 +23,11 @@ def serialize_and_recover(file_sources_o: ConfiguredFileSources, user_context: O
return file_sources
-def find_file_a(dir_list: list[AnyRemoteEntry]) -> Optional[AnyRemoteEntry]:
+def find_file_a(dir_list: list[AnyRemoteEntry]) -> AnyRemoteEntry | None:
return find(dir_list, class_="File", name="a")
-def find(dir_list: list[AnyRemoteEntry], class_=None, name=None) -> Optional[AnyRemoteEntry]:
+def find(dir_list: list[AnyRemoteEntry], class_=None, name=None) -> AnyRemoteEntry | None:
for ent in dir_list:
if class_ is not None and ent.class_ != class_:
continue
@@ -161,7 +160,7 @@ def write_from(
return file_source_path.file_source.write_from(file_source_path.path, f.name, user_context=user_context)
-def configured_file_sources(conf_file, file_sources_config: Optional[FileSourcePluginsConfig] = None):
+def configured_file_sources(conf_file, file_sources_config: FileSourcePluginsConfig | None = None):
file_sources_config = file_sources_config or FileSourcePluginsConfig()
assert file_sources_config
if isinstance(conf_file, str):
diff --git a/test/unit/files/test_ascp.py b/test/unit/files/test_ascp.py
index 965ea9029b9..98f4a02d4ec 100644
--- a/test/unit/files/test_ascp.py
+++ b/test/unit/files/test_ascp.py
@@ -338,7 +338,6 @@ class TestAscpFilesSource:
}
with patch("shutil.which", return_value="/usr/bin/ascp"):
-
with tempfile.NamedTemporaryFile(mode="w", suffix=".yml", delete=False) as f:
import yaml
diff --git a/test/unit/files/test_irods.py b/test/unit/files/test_irods.py
index 8396dc108e0..4ac791be709 100644
--- a/test/unit/files/test_irods.py
+++ b/test/unit/files/test_irods.py
@@ -57,9 +57,8 @@ def _irods_live_settings() -> dict:
with open(config_path, "rb") as handle:
configs = yaml.safe_load(handle) or []
- irods_id = os.environ.get("GALAXY_TEST_IRODS_SOURCE_ID")
irods_configs = [c for c in configs if isinstance(c, dict) and c.get("type") == "irods"]
- if irods_id:
+ if irods_id := os.environ.get("GALAXY_TEST_IRODS_SOURCE_ID"):
irods_configs = [c for c in irods_configs if c.get("id") == irods_id]
if not irods_configs:
diff --git a/test/unit/job_metrics/test_job_metrics.py b/test/unit/job_metrics/test_job_metrics.py
index bb9acb053b8..a4922b4909e 100644
--- a/test/unit/job_metrics/test_job_metrics.py
+++ b/test/unit/job_metrics/test_job_metrics.py
@@ -1,6 +1,5 @@
from typing import (
Any,
- Optional,
)
from galaxy.job_metrics import (
@@ -119,9 +118,7 @@ def _assert_metrics_of_type(metric_list, expected_types):
assert dictifiable_metric.plugin == expected_type
-def _assert_format(
- plugin: str, key: str, value: Any, assert_title: Optional[str] = None, assert_value: Optional[str] = None
-):
+def _assert_format(plugin: str, key: str, value: Any, assert_title: str | None = None, assert_value: str | None = None):
result = TEST_JOBS_METRICS.format(plugin, key, value)
if assert_title is not None:
assert result[0] == assert_title
diff --git a/test/unit/schema/test_schema.py b/test/unit/schema/test_schema.py
index 07d2cb3b3d5..ea56dcfbeca 100644
--- a/test/unit/schema/test_schema.py
+++ b/test/unit/schema/test_schema.py
@@ -42,7 +42,6 @@ def test_dataset_state_coercion():
class TestTagPattern:
-
def test_valid(self):
tag_strings = [
"a",
diff --git a/test/unit/selenium/test_server.py b/test/unit/selenium/test_server.py
index b0f23a1afe2..fdb9d0d7147 100644
--- a/test/unit/selenium/test_server.py
+++ b/test/unit/selenium/test_server.py
@@ -4,13 +4,12 @@ import http.server
import socketserver
import threading
from pathlib import Path
-from typing import Optional
class TestHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
"""Custom request handler for serving test HTML files."""
- def __init__(self, *args, directory: Optional[str] = None, **kwargs):
+ def __init__(self, *args, directory: str | None = None, **kwargs):
"""Initialize handler with custom directory."""
super().__init__(*args, directory=directory, **kwargs)
@@ -27,7 +26,7 @@ class TestHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
class TestHTTPServer:
"""Simple HTTP server for serving test HTML pages."""
- def __init__(self, port: int = 0, directory: Optional[Path] = None):
+ def __init__(self, port: int = 0, directory: Path | None = None):
"""
Initialize test HTTP server.
@@ -37,8 +36,8 @@ class TestHTTPServer:
"""
self.port = port
self.directory = directory or Path(__file__).parent / "fixtures"
- self.server: Optional[socketserver.TCPServer] = None
- self.thread: Optional[threading.Thread] = None
+ self.server: socketserver.TCPServer | None = None
+ self.thread: threading.Thread | None = None
def start(self):
"""Start the HTTP server in a background thread."""
diff --git a/test/unit/selenium/util.py b/test/unit/selenium/util.py
index 20142ac9b2e..2733eef87ad 100644
--- a/test/unit/selenium/util.py
+++ b/test/unit/selenium/util.py
@@ -3,7 +3,6 @@
from collections.abc import Callable
from typing import (
TypeVar,
- Union,
)
import pytest
@@ -27,7 +26,7 @@ def _identity(func: Callable[P, T]) -> Callable[P, T]:
return func
-def skip_unless_selenium_browser() -> Union[Callable[[Callable[P, T]], Callable[P, T]], pytest.MarkDecorator]:
+def skip_unless_selenium_browser() -> Callable[[Callable[P, T]], Callable[P, T]] | pytest.MarkDecorator:
"""
Skip test if Selenium Chrome browser is not available.
@@ -39,7 +38,7 @@ def skip_unless_selenium_browser() -> Union[Callable[[Callable[P, T]], Callable[
return pytest.mark.skip(SELENIUM_BROWSER_NOT_AVAILABLE_MESSAGE)
-def skip_unless_playwright_browser() -> Union[Callable[[Callable[P, T]], Callable[P, T]], pytest.MarkDecorator]:
+def skip_unless_playwright_browser() -> Callable[[Callable[P, T]], Callable[P, T]] | pytest.MarkDecorator:
"""
Skip test if Playwright Chromium browser is not available.
@@ -51,7 +50,7 @@ def skip_unless_playwright_browser() -> Union[Callable[[Callable[P, T]], Callabl
return pytest.mark.skip(PLAYWRIGHT_BROWSER_NOT_AVAILABLE_MESSAGE)
-def skip_unless_selenium_browser_cached() -> Union[Callable[[Callable[P, T]], Callable[P, T]], pytest.MarkDecorator]:
+def skip_unless_selenium_browser_cached() -> Callable[[Callable[P, T]], Callable[P, T]] | pytest.MarkDecorator:
"""
Skip test if Selenium Chrome browser is not available (cached check).
@@ -66,7 +65,7 @@ def skip_unless_selenium_browser_cached() -> Union[Callable[[Callable[P, T]], Ca
return pytest.mark.skip(SELENIUM_BROWSER_NOT_AVAILABLE_MESSAGE)
-def skip_unless_playwright_browser_cached() -> Union[Callable[[Callable[P, T]], Callable[P, T]], pytest.MarkDecorator]:
+def skip_unless_playwright_browser_cached() -> Callable[[Callable[P, T]], Callable[P, T]] | pytest.MarkDecorator:
"""
Skip test if Playwright Chromium browser is not available (cached check).
diff --git a/test/unit/tool_shed/_util.py b/test/unit/tool_shed/_util.py
index ed711aa347f..166035ea648 100644
--- a/test/unit/tool_shed/_util.py
+++ b/test/unit/tool_shed/_util.py
@@ -9,7 +9,6 @@ from tempfile import (
)
from typing import (
Any,
- Optional,
)
from galaxy.security.idencoding import IdEncodingHelper
@@ -45,8 +44,8 @@ class TestToolShedConfig:
user_activation_on = False
file_path: str
id_secret: str = "thisistheshedunittestsecret"
- smtp_server: Optional[str] = None
- tool_shed_url: Optional[str] = "shed_unit_test://localhost"
+ smtp_server: str | None = None
+ tool_shed_url: str | None = "shed_unit_test://localhost"
hgweb_repo_prefix = "repos/"
config_hg_for_dev = False
@@ -83,7 +82,7 @@ class TestToolShedApp(ToolShedApp):
self.security_agent = self.model.security_agent
-def user_fixture(app: ToolShedApp, username: str, password: str = "testpassword", email: Optional[str] = None) -> User:
+def user_fixture(app: ToolShedApp, username: str, password: str = "testpassword", email: str | None = None) -> User:
email = email or f"{username}@galaxyproject.org"
return create_user(
app,
@@ -118,7 +117,7 @@ def provides_repositories_fixture(
return ProvidesRepositoriesImpl(app, user)
-def repository_fixture(app: ToolShedApp, user: User, name: str, category: Optional[Category] = None) -> Repository:
+def repository_fixture(app: ToolShedApp, user: User, name: str, category: Category | None = None) -> Repository:
type = rt_util.UNRESTRICTED
description = f"test repo named {name}"
long_description = f"test repo named {name} a longer description"
@@ -153,7 +152,7 @@ def upload(
provides_repositories: ProvidesRepositoriesContext,
repository: Repository,
path: Path,
- arcname: Optional[str] = None,
+ arcname: str | None = None,
):
if path.is_dir():
tf = NamedTemporaryFile(delete=False)
diff --git a/test/unit/tool_shed/test_tool_panel_manager.py b/test/unit/tool_shed/test_tool_panel_manager.py
index c43005d3715..67af9e31721 100644
--- a/test/unit/tool_shed/test_tool_panel_manager.py
+++ b/test/unit/tool_shed/test_tool_panel_manager.py
@@ -1,5 +1,4 @@
import os
-from typing import Optional
from galaxy.app_unittest_utils.toolbox_support import (
BaseToolBoxTestCase,
@@ -77,7 +76,7 @@ class TestToolPanelManager(BaseToolBoxTestCase):
def test_add_twice(self):
self._init_dynamic_tool_conf()
- previous_guid: Optional[str] = None
+ previous_guid: str | None = None
for v in "1", "2", "3":
self.__toolbox = self.get_new_toolbox()
changeset = f"0123456789abcde{v}"
diff --git a/test/unit/tool_util/test_edam_util.py b/test/unit/tool_util/test_edam_util.py
index e982e1c3b37..0ec59cbf85b 100644
--- a/test/unit/tool_util/test_edam_util.py
+++ b/test/unit/tool_util/test_edam_util.py
@@ -1,7 +1,6 @@
import tempfile
from typing import (
Any,
- Dict,
)
from edam_ontology.streams import tabular_stream
@@ -22,7 +21,7 @@ def test_load_edam_tree_from_path():
_verify_tree(tree)
-def _verify_tree(tree: Dict[str, Any]):
+def _verify_tree(tree: dict[str, Any]):
assert tree is not None
assert "operation_0004" in tree
assert "topic_3974" in tree
diff --git a/test/unit/tool_util/test_parameter_convert.py b/test/unit/tool_util/test_parameter_convert.py
index 26e4a5b6cb4..946be736a49 100644
--- a/test/unit/tool_util/test_parameter_convert.py
+++ b/test/unit/tool_util/test_parameter_convert.py
@@ -1,7 +1,5 @@
from typing import (
Any,
- Dict,
- Optional,
)
from galaxy.tool_util.parameters import (
@@ -39,7 +37,7 @@ EXAMPLE_ID_1 = 13
EXAMPLE_ID_2_ENCODED = "123456789abcd2"
EXAMPLE_ID_2 = 14
-ID_MAP: Dict[int, str] = {
+ID_MAP: dict[int, str] = {
EXAMPLE_ID_1: EXAMPLE_ID_1_ENCODED,
EXAMPLE_ID_2: EXAMPLE_ID_2_ENCODED,
}
@@ -174,7 +172,7 @@ def test_dereference():
request_state = RequestInternalToolState(raw_request_state)
request_state.validate(bundle)
- exception: Optional[Exception] = None
+ exception: Exception | None = None
try:
# quickly verify this request needs to be dereferenced
bad_state = RequestInternalDereferencedToolState(raw_request_state)
@@ -389,7 +387,7 @@ def test_strictify():
assert strict_state["parameter"] == ""
-def strictify_for(tool_state: Dict[str, Any], tool_path: str) -> Dict[str, Any]:
+def strictify_for(tool_state: dict[str, Any], tool_path: str) -> dict[str, Any]:
tool_source = tool_source_for(tool_path)
bundle = input_models_for_tool_source(tool_source)
relaxed_state = RelaxedRequestToolState(tool_state)
@@ -401,7 +399,7 @@ def strictify_for(tool_state: Dict[str, Any], tool_path: str) -> Dict[str, Any]:
# Keying on the URL (rather than returning a constant) makes the dereference tests assert the
# *configured* URL actually reached the dereference boundary - an unexpected/empty URL raises
# KeyError instead of silently passing.
-URL_ID_MAP: Dict[str, int] = {
+URL_ID_MAP: dict[str, int] = {
"https://example.com/1.bed": EXAMPLE_ID_1,
"gxfiles://mystorage/1.bed": EXAMPLE_ID_2,
}
@@ -424,7 +422,7 @@ def _fake_encode(input: int) -> str:
def _strict_async_decode_and_dereference(
- tool_state: Dict[str, Any], bundle: ToolParameterBundleModel
+ tool_state: dict[str, Any], bundle: ToolParameterBundleModel
) -> RequestInternalDereferencedToolState:
request_state = RequestToolState(tool_state)
request_state.validate(bundle)
@@ -432,7 +430,7 @@ def _strict_async_decode_and_dereference(
return dereference(request_internal_state, bundle, _fake_dereference, _fake_collection_deference)
-def fill_state_for(tool_state: Dict[str, Any], tool_path: str, partial: bool = False) -> Dict[str, Any]:
+def fill_state_for(tool_state: dict[str, Any], tool_path: str, partial: bool = False) -> dict[str, Any]:
tool_source = tool_source_for(tool_path)
bundle = input_models_for_tool_source(tool_source)
profile = parse_profile_version(tool_source)
diff --git a/test/unit/tool_util/test_parameter_specification.py b/test/unit/tool_util/test_parameter_specification.py
index c08e3d1f4c3..d331647c2ac 100644
--- a/test/unit/tool_util/test_parameter_specification.py
+++ b/test/unit/tool_util/test_parameter_specification.py
@@ -1,10 +1,6 @@
import json
+from collections.abc import Callable
from functools import partial
-from typing import (
- Callable,
- List,
- Optional,
-)
import yaml
@@ -93,7 +89,7 @@ def test_single():
_test_file("gx_conditional_boolean_checked")
-def _test_file(file: str, specification=None, parameter_bundle: Optional[ToolParameterBundleModel] = None):
+def _test_file(file: str, specification=None, parameter_bundle: ToolParameterBundleModel | None = None):
spec = specification or specification_object()
combos = spec[file]
if parameter_bundle is None:
@@ -140,7 +136,7 @@ def _test_file(file: str, specification=None, parameter_bundle: Optional[ToolPar
_assert_internal_requests_invalid(parameter_bundle, combos["request_invalid"])
-def _for_each(test: Callable, parameters: ToolParameterBundleModel, requests: List[RawStateDict]) -> None:
+def _for_each(test: Callable, parameters: ToolParameterBundleModel, requests: list[RawStateDict]) -> None:
for request in requests:
test(parameters, request)
diff --git a/test/unit/tool_util/test_parameter_specification_json_schema.py b/test/unit/tool_util/test_parameter_specification_json_schema.py
index 7cc1aab90a4..1cee53e5ed3 100644
--- a/test/unit/tool_util/test_parameter_specification_json_schema.py
+++ b/test/unit/tool_util/test_parameter_specification_json_schema.py
@@ -14,11 +14,6 @@ knows to tolerate those *_invalid entries passing validation.
import sys
from typing import (
Any,
- Dict,
- List,
- Optional,
- Set,
- Tuple,
)
import jsonschema
@@ -58,7 +53,7 @@ REPRESENTATION_KEYS = [
"workflow_step_linked",
]
-STATE_REPRESENTATION_FOR_KEY: Dict[str, StateRepresentationT] = {k: k for k in REPRESENTATION_KEYS} # type: ignore[misc]
+STATE_REPRESENTATION_FOR_KEY: dict[str, StateRepresentationT] = {k: k for k in REPRESENTATION_KEYS} # type: ignore[misc]
def specification_object():
@@ -69,7 +64,7 @@ def specification_object():
return yaml.safe_load(yaml_str)
-def _json_schema_for(bundle: ToolParameterBundleModel, state_representation: StateRepresentationT) -> Dict[str, Any]:
+def _json_schema_for(bundle: ToolParameterBundleModel, state_representation: StateRepresentationT) -> dict[str, Any]:
model = create_field_model(bundle.parameters, name="TestModel", state_representation=state_representation)
return to_json_schema(model)
@@ -87,7 +82,7 @@ def _check_color_format(value: object) -> bool:
return True
-def _json_schema_validates(schema: Dict[str, Any], state_dict: RawStateDict) -> bool:
+def _json_schema_validates(schema: dict[str, Any], state_dict: RawStateDict) -> bool:
validator = jsonschema.Draft202012Validator(schema, format_checker=_FORMAT_CHECKER)
errors = list(validator.iter_errors(state_dict))
return len(errors) == 0
@@ -96,7 +91,7 @@ def _json_schema_validates(schema: Dict[str, Any], state_dict: RawStateDict) ->
def _test_file_json_schema(
file: str,
specification=None,
- parameter_bundle: Optional[ToolParameterBundleModel] = None,
+ parameter_bundle: ToolParameterBundleModel | None = None,
):
spec = specification or specification_object()
combos = spec[file]
@@ -104,12 +99,12 @@ def _test_file_json_schema(
parameter_bundle = parameter_bundle_for_file(file)
assert parameter_bundle
- json_schema_skip: Dict[str, str] = combos.get("_json_schema_skip", {}) or {}
- json_schema_valid_skip: Dict[str, str] = combos.get("_json_schema_valid_skip", {}) or {}
- skipped_invalid_keys: Set[str] = set(json_schema_skip.keys())
- skipped_valid_keys: Set[str] = set(json_schema_valid_skip.keys())
+ json_schema_skip: dict[str, str] = combos.get("_json_schema_skip", {}) or {}
+ json_schema_valid_skip: dict[str, str] = combos.get("_json_schema_valid_skip", {}) or {}
+ skipped_invalid_keys: set[str] = set(json_schema_skip.keys())
+ skipped_valid_keys: set[str] = set(json_schema_valid_skip.keys())
- failures: List[str] = []
+ failures: list[str] = []
for combo_key, test_cases in combos.items():
if combo_key in ("_json_schema_skip", "_json_schema_valid_skip"):
@@ -156,7 +151,7 @@ def test_specification_json_schema():
def _conditional_type_def(
file: str, state_representation: StateRepresentationT = "request"
-) -> Tuple[Dict[str, Any], Dict[str, Any]]:
+) -> tuple[dict[str, Any], dict[str, Any]]:
bundle = parameter_bundle_for_file(file)
schema = _json_schema_for(bundle, state_representation)
defs = schema.get("$defs", {})
diff --git a/test/unit/tool_util/test_parameter_test_cases.py b/test/unit/tool_util/test_parameter_test_cases.py
index 791be010dca..a3466456551 100644
--- a/test/unit/tool_util/test_parameter_test_cases.py
+++ b/test/unit/tool_util/test_parameter_test_cases.py
@@ -2,9 +2,6 @@ import os
import re
from typing import (
Any,
- List,
- Optional,
- Tuple,
)
import pytest
@@ -96,7 +93,7 @@ def test_legacy_features_fail_validation_with_24_2(tmp_path):
_assert_tool_test_parsing_only_fails_with_newer_profile(tmp_path, "multi_select.xml", index=1)
-def _assert_tool_test_parsing_only_fails_with_newer_profile(tmp_path, filename: str, index: Optional[int] = 0):
+def _assert_tool_test_parsing_only_fails_with_newer_profile(tmp_path, filename: str, index: int | None = 0):
test_tool_directory = functional_test_tool_directory()
original_path = os.path.join(test_tool_directory, filename)
new_path = tmp_path / filename
@@ -144,9 +141,9 @@ def test_validate_framework_test_tools():
def test_test_case_state_conversion():
tool_source = tool_source_for("collection_nested_test")
- test_cases: List[ToolSourceTest] = tool_source.parse_tests_to_dict()["tests"]
+ test_cases: list[ToolSourceTest] = tool_source.parse_tests_to_dict()["tests"]
state = case_state_for(tool_source, test_cases[0])
- expectations: List[Tuple[List[Any], Optional[Any]]]
+ expectations: list[tuple[list[Any], Any | None]]
expectations = [
(["f1", "collection_type"], "list:paired"),
(["f1", "class"], "Collection"),
@@ -704,7 +701,7 @@ def test_convert_to_requests():
parameters = input_models_for_tool_source(tool_source)
parsed_tool = parse_tool(tool_source)
profile = tool_source.parse_profile()
- test_cases: List[ToolSourceTest] = tool_source.parse_tests_to_dict()["tests"]
+ test_cases: list[ToolSourceTest] = tool_source.parse_tests_to_dict()["tests"]
def mock_adapt_datasets(input: JsonTestDatasetDefDict) -> DataRequestHda:
return DataRequestHda(src="hda", id=MOCK_ID)
@@ -732,7 +729,7 @@ def _validate_path(tool_path: str):
model_name = f"{tool_id} (test case model)"
parsed_tool = parse_tool(tool_source)
profile = tool_source.parse_profile()
- test_cases: List[ToolSourceTest] = tool_source.parse_tests_to_dict()["tests"]
+ test_cases: list[ToolSourceTest] = tool_source.parse_tests_to_dict()["tests"]
for test_case in test_cases:
if test_case.get("expect_failure"):
continue
@@ -741,7 +738,7 @@ def _validate_path(tool_path: str):
assert tool_state.state_representation == "test_case_xml"
-def validate_test_cases_for(tool_name: str, **kwd) -> List[TestCaseStateValidationResult]:
+def validate_test_cases_for(tool_name: str, **kwd) -> list[TestCaseStateValidationResult]:
return validate_test_cases_for_tool_source(tool_source_for(tool_name), **kwd)
diff --git a/test/unit/tool_util/test_parameter_validator_models.py b/test/unit/tool_util/test_parameter_validator_models.py
index 17af98f2ce6..1e4ea348777 100644
--- a/test/unit/tool_util/test_parameter_validator_models.py
+++ b/test/unit/tool_util/test_parameter_validator_models.py
@@ -1,5 +1,3 @@
-from typing import Optional
-
from galaxy.tool_util.parser.parameter_validators import parse_xml_validators
from galaxy.tool_util.unittest_utils.sample_data import (
INVALID_XML_VALIDATORS,
@@ -15,7 +13,7 @@ def test_xml_validation_valid():
def test_xml_validation_invalid():
for xml_validator in INVALID_XML_VALIDATORS:
- exc: Optional[Exception] = None
+ exc: Exception | None = None
try:
_validate_xml_str(xml_validator)
except ValueError as e:
diff --git a/test/unit/tool_util/test_parsing.py b/test/unit/tool_util/test_parsing.py
index ffb7c7ce31e..fdf5c8bf2f8 100644
--- a/test/unit/tool_util/test_parsing.py
+++ b/test/unit/tool_util/test_parsing.py
@@ -2,11 +2,9 @@ import os
import os.path
import shutil
import tempfile
+from collections.abc import Sequence
from math import isinf
from typing import (
- Optional,
- Sequence,
- Type,
TypeVar,
)
@@ -279,8 +277,8 @@ def get_test_tool_source(source_file_name=None, source_contents=None, macro_cont
class BaseLoaderTestCase(TestCase):
- source_file_name: Optional[str] = None
- source_contents: Optional[str] = None
+ source_file_name: str | None = None
+ source_contents: str | None = None
def setUp(self):
self.temp_directory = tempfile.mkdtemp()
@@ -1102,6 +1100,6 @@ class TestToolProvidedMetadata2(FunctionalTestToolTestCase):
T = TypeVar("T")
-def assert_output_model_of_type(obj, clazz: Type[T]) -> T:
+def assert_output_model_of_type(obj, clazz: type[T]) -> T:
assert isinstance(obj, clazz)
return obj
diff --git a/test/unit/tool_util/test_test_definition_parsing.py b/test/unit/tool_util/test_test_definition_parsing.py
index f49b105128e..d32eedacb54 100644
--- a/test/unit/tool_util/test_test_definition_parsing.py
+++ b/test/unit/tool_util/test_test_definition_parsing.py
@@ -3,7 +3,6 @@
import os
from typing import (
Any,
- List,
)
from pytest import skip
@@ -177,7 +176,7 @@ class TestTestParsing(TestCase):
for td in test_dicts:
assert not td.get("exception"), f"Test failed to parse: {td.get('exception')}"
- def _verify_each(self, target_dict: dict, expectations: List[Any]):
+ def _verify_each(self, target_dict: dict, expectations: list[Any]):
exception = target_dict.get("exception")
assert not exception, f"Test failed to generate with exception {exception}"
dict_verify_each(target_dict, expectations)
diff --git a/test/unit/tool_util/test_test_format_model.py b/test/unit/tool_util/test_test_format_model.py
index 5f460385dd4..67960cd3db6 100644
--- a/test/unit/tool_util/test_test_format_model.py
+++ b/test/unit/tool_util/test_test_format_model.py
@@ -1,6 +1,5 @@
import os
from pathlib import Path
-from typing import List
import pytest
import yaml
@@ -12,14 +11,14 @@ from galaxy.util import galaxy_directory
from galaxy.util.unittest_utils import skip_unless_environ
TEST_WORKFLOW_DIRECTORY = os.path.join(galaxy_directory(), "lib", "galaxy_test", "workflow")
-IWC_WORKFLOWS_USING_UNVERIFIED_SYNTAX: List[str] = []
+IWC_WORKFLOWS_USING_UNVERIFIED_SYNTAX: list[str] = []
# replacement_parameters_legacy.gxwf-tests.yml is a deliberate regression test
# for Planemo-era implicit replacement_parameters: {...} dicts embedded in
# job:. That key is popped out by WorkflowPopulator.run_workflow before
# staging, so the runtime accepts it but it is not canonical workflow-test
# input syntax and the strict Job schema does not model it.
-WORKFLOW_TESTS_SKIP_STRICT_VALIDATION: List[str] = [
+WORKFLOW_TESTS_SKIP_STRICT_VALIDATION: list[str] = [
"replacement_parameters_legacy.gxwf-tests.yml",
]
diff --git a/test/unit/tool_util/test_tool_deps.py b/test/unit/tool_util/test_tool_deps.py
index 172b7d25623..50f694daf75 100644
--- a/test/unit/tool_util/test_tool_deps.py
+++ b/test/unit/tool_util/test_tool_deps.py
@@ -15,8 +15,6 @@ from subprocess import (
)
from typing import (
Any,
- Dict,
- Optional,
)
from galaxy.tool_util.deps import (
@@ -802,7 +800,7 @@ def test_dependency_manager_config_options_global():
def test_dependency_manager_config_options_embedded_config():
- dependency_config: Dict[str, Any] = {
+ dependency_config: dict[str, Any] = {
"default_base_path": "/tmp",
"cache_dir": "/tmp",
}
@@ -835,7 +833,7 @@ def test_dependency_manager_config_options_resolution_config():
app_config = {
"conda_auto_init": False,
}
- resolution_config: Dict[str, Any] = {
+ resolution_config: dict[str, Any] = {
"default_base_path": "/tmp",
"cache_dir": "/tmp",
}
@@ -899,7 +897,7 @@ def __dependency_manager(file_content, extension=".xml"):
yield dm
-def __dependency_manager_for_base_path(default_base_path: str, conf_file: Optional[str] = None) -> DependencyManager:
+def __dependency_manager_for_base_path(default_base_path: str, conf_file: str | None = None) -> DependencyManager:
dm = DependencyManager(
default_base_path=default_base_path, conf_file=conf_file, app_config={"conda_auto_init": False}
)
diff --git a/test/unit/tool_util/test_user_tool_source_fixtures.py b/test/unit/tool_util/test_user_tool_source_fixtures.py
index bb4628861be..da5e61dc728 100644
--- a/test/unit/tool_util/test_user_tool_source_fixtures.py
+++ b/test/unit/tool_util/test_user_tool_source_fixtures.py
@@ -11,7 +11,6 @@ instead of only an API integration.
"""
import os
-from typing import List
import pytest
import yaml
@@ -32,10 +31,10 @@ _LEGACY_FIXTURES = {
_dynamic_tool_source_adapter: TypeAdapter = TypeAdapter(DynamicToolSources)
-def _collect_yaml_tool_fixtures() -> List[str]:
+def _collect_yaml_tool_fixtures() -> list[str]:
root = functional_test_tool_directory()
directories = [root, os.path.join(root, "parameters")]
- paths: List[str] = []
+ paths: list[str] = []
for directory in directories:
if not os.path.isdir(directory):
continue
diff --git a/test/unit/tool_util/test_user_tool_source_validation.py b/test/unit/tool_util/test_user_tool_source_validation.py
index 5759d9ae2f7..70c2fe2e4fc 100644
--- a/test/unit/tool_util/test_user_tool_source_validation.py
+++ b/test/unit/tool_util/test_user_tool_source_validation.py
@@ -15,8 +15,6 @@ from copy import deepcopy
from pathlib import Path
from typing import (
Any,
- Dict,
- List,
)
import pytest
@@ -29,7 +27,7 @@ from galaxy.tool_util_models import (
)
from galaxy.util.resources import resource_string
-VALID_TOOL: Dict[str, Any] = {
+VALID_TOOL: dict[str, Any] = {
"class": "GalaxyUserTool",
"id": "my-cool-tool",
"name": "My Cool Tool",
@@ -50,7 +48,7 @@ VALID_TOOL: Dict[str, Any] = {
}
-def _load_cases() -> List[Dict[str, Any]]:
+def _load_cases() -> list[dict[str, Any]]:
try:
yaml_str = resource_string(__name__, "user_tool_source_validation_cases.yml")
except AttributeError:
@@ -63,7 +61,7 @@ def _load_cases() -> List[Dict[str, Any]]:
CASES = _load_cases()
-def _doc_for(case: Dict[str, Any]) -> Dict[str, Any]:
+def _doc_for(case: dict[str, Any]) -> dict[str, Any]:
base = deepcopy(VALID_TOOL)
base.update(case.get("doc") or {})
return base
@@ -76,7 +74,7 @@ def _flatten_loc(loc: Any) -> str:
@pytest.mark.parametrize("case", CASES, ids=lambda c: c["name"])
-def test_user_tool_source_corpus(case: Dict[str, Any]) -> None:
+def test_user_tool_source_corpus(case: dict[str, Any]) -> None:
doc = _doc_for(case)
if case.get("valid"):
UserToolSource.model_validate(doc)
diff --git a/test/unit/tool_util/test_util.py b/test/unit/tool_util/test_util.py
index 2a1de73abd5..d0dd59514a4 100644
--- a/test/unit/tool_util/test_util.py
+++ b/test/unit/tool_util/test_util.py
@@ -1,5 +1,4 @@
from os import environ
-from typing import Dict
import pytest
@@ -64,7 +63,7 @@ def test_modify_environ__update_and_restore(load_keyval):
def test_modify_environ__remove_and_restore(load_keyval):
key1, val1 = load_keyval()
key2, val2 = load_keyval("key to remove", "value to remove")
- to_update: Dict[str, str] = {}
+ to_update: dict[str, str] = {}
to_remove = [key2]
with modify_environ(to_update, to_remove):
@@ -78,7 +77,7 @@ def test_modify_environ__remove_nonexistant_key(load_keyval):
# Test that removing wrong key does not raise an error
key1, val1 = load_keyval()
key_nonexistant = "no such key"
- to_update: Dict[str, str] = {}
+ to_update: dict[str, str] = {}
to_remove = [key_nonexistant]
assert key_nonexistant not in environ # ensure key to remove does not exist
diff --git a/test/unit/tool_util/test_verify.py b/test/unit/tool_util/test_verify.py
index 523ae319756..68254f30235 100644
--- a/test/unit/tool_util/test_verify.py
+++ b/test/unit/tool_util/test_verify.py
@@ -5,11 +5,6 @@ import math
import tempfile
from typing import (
Any,
- Dict,
- List,
- Optional,
- Tuple,
- Type,
)
import numpy
@@ -32,7 +27,7 @@ F4 = b"A\r\nB\nC"
MULTILINE_MATCH = b".*"
TestFile = collections.namedtuple("TestFile", "value path")
-TestDef = Tuple[bytes, bytes, Optional[Dict[str, Any]], Optional[Type[AssertionError]]]
+TestDef = tuple[bytes, bytes, dict[str, Any] | None, type[AssertionError] | None]
def _encode_image(im, **kwargs):
@@ -125,7 +120,7 @@ def _test_file_list():
def generate_tests(multiline=False):
f1, f2, f3, f4, multiline_match, f5, f6, f7, f8, f9, f10 = _test_file_list()
- tests: List[TestDef]
+ tests: list[TestDef]
if multiline:
tests = [(multiline_match, f1, {"lines_diff": 0, "sort": True}, None)]
else:
@@ -144,7 +139,7 @@ def generate_tests(multiline=False):
def generate_tests_sim_size():
f1, f2, f3, f4, multiline_match, f5, f6, f7, f8, f9, f10 = _test_file_list()
# tests for equal files
- tests: List[TestDef] = [
+ tests: list[TestDef] = [
(f1, f1, None, None), # pass default values
(f1, f1, {"delta": 0}, None), # pass for values that should always pass
(f1, f1, {"delta_frac": 0.0}, None),
@@ -171,7 +166,7 @@ def generate_tests_image_diff():
f1, f2, f3, f4, multiline_match, f5, f6, f7, f8, f9, f10 = _test_file_list()
metrics = ["mae", "mse", "rms", "fro", "iou"]
# tests for equal files (uint8, PNG)
- tests: List[TestDef] = [(f6, f6, {"metric": metric}, None) for metric in metrics]
+ tests: list[TestDef] = [(f6, f6, {"metric": metric}, None) for metric in metrics]
# tests for equal files (uint8, TIFF)
tests += [(f7, f7, {"metric": metric}, None) for metric in metrics]
# tests for equal files (float, TIFF)
diff --git a/test/unit/tool_util/test_verify_hid.py b/test/unit/tool_util/test_verify_hid.py
index e1db48cc616..c021c75d2d9 100644
--- a/test/unit/tool_util/test_verify_hid.py
+++ b/test/unit/tool_util/test_verify_hid.py
@@ -1,17 +1,11 @@
-from typing import (
- Callable,
- Dict,
- Optional,
-)
+from collections.abc import Callable
from galaxy.tool_util.unittest_utils import t_data_downloader_for
from galaxy.tool_util.verify.interactor import verify_hid
-def dataset_fetcher_for(
- expected_hda_id: str, content: Dict[Optional[str], bytes]
-) -> Callable[[str, Optional[str]], bytes]:
- def get_content(hda_id, filename: Optional[str] = None) -> bytes:
+def dataset_fetcher_for(expected_hda_id: str, content: dict[str | None, bytes]) -> Callable[[str, str | None], bytes]:
+ def get_content(hda_id, filename: str | None = None) -> bytes:
assert expected_hda_id == hda_id
return content[filename]
diff --git a/test/unit/tool_util/upgrade/test_upgrade_advice.py b/test/unit/tool_util/upgrade/test_upgrade_advice.py
index 3fbd0635928..18ab9ad0cdf 100644
--- a/test/unit/tool_util/upgrade/test_upgrade_advice.py
+++ b/test/unit/tool_util/upgrade/test_upgrade_advice.py
@@ -2,7 +2,6 @@
# - 21_09_fix_from_work_dir_whitespace
# - 23_0_consider_optional_text
import os
-from typing import List
import pytest
@@ -160,7 +159,7 @@ def _tool_path(tool_name: str):
return os.path.join(functional_test_tool_path(tool_name))
-def assert_has_advice(advice_list: List[Advice], advice_code: str):
+def assert_has_advice(advice_list: list[Advice], advice_code: str):
for advice in advice_list:
if advice.advice_code["name"] == advice_code:
return
@@ -168,7 +167,7 @@ def assert_has_advice(advice_list: List[Advice], advice_code: str):
raise AssertionError(f"Was expecting advice {advice_code} in list of upgrade advice {advice_list}")
-def assert_not_has_advice(advice_list: List[Advice], advice_code: str):
+def assert_not_has_advice(advice_list: list[Advice], advice_code: str):
for advice in advice_list:
if advice.advice_code["name"] == advice_code:
raise AssertionError(f"Was not expecting advice {advice_code} in list of upgrade advice {advice_list}")
diff --git a/test/unit/tool_util/util.py b/test/unit/tool_util/util.py
index 27f0ee677fb..49bcb2fb2cc 100644
--- a/test/unit/tool_util/util.py
+++ b/test/unit/tool_util/util.py
@@ -3,7 +3,6 @@ from contextlib import contextmanager
from os import environ
from typing import (
Any,
- List,
)
import pytest
@@ -11,7 +10,7 @@ import pytest
external_dependency_management = pytest.mark.external_dependency_management
-def dict_verify_each(target_dict: dict, expectations: List[Any]):
+def dict_verify_each(target_dict: dict, expectations: list[Any]):
assert_json_encodable(target_dict)
for path, expectation in expectations:
exception = target_dict.get("exception")
@@ -19,7 +18,7 @@ def dict_verify_each(target_dict: dict, expectations: List[Any]):
dict_verify(target_dict, path, expectation)
-def dict_verify(target_dict: dict, expectation_path: List[Any], expectation: Any):
+def dict_verify(target_dict: dict, expectation_path: list[Any], expectation: Any):
rest = target_dict
for path_part in expectation_path:
rest = rest[path_part]
diff --git a/test/unit/tool_util/verify/test_asserts.py b/test/unit/tool_util/verify/test_asserts.py
index fc4b06e9086..ef721503bc7 100644
--- a/test/unit/tool_util/verify/test_asserts.py
+++ b/test/unit/tool_util/verify/test_asserts.py
@@ -2,7 +2,6 @@ import gzip
import os
import shutil
import tempfile
-from typing import Tuple
try:
import h5py
@@ -1324,7 +1323,7 @@ if h5py is not None:
assert len(a) == 1
-def run_assertions(assertion_xml: str, data, decompress=False) -> Tuple:
+def run_assertions(assertion_xml: str, data, decompress=False) -> tuple:
assertion = parse_xml_string(assertion_xml)
assertion_description = __parse_assert_list_from_elem(assertion)
assert assertion_description
diff --git a/test/unit/tool_util_models/test_user_tool_source_response.py b/test/unit/tool_util_models/test_user_tool_source_response.py
index 290f409a5ff..0aca069150b 100644
--- a/test/unit/tool_util_models/test_user_tool_source_response.py
+++ b/test/unit/tool_util_models/test_user_tool_source_response.py
@@ -9,7 +9,6 @@ the API doesn't 500. See Sentry GALAXY-TEST-588ZYT7JSX3V0.
from typing import (
Any,
- Dict,
)
from galaxy.tool_util_models import (
@@ -21,7 +20,7 @@ from galaxy.tool_util_models.tool_outputs import (
IncomingToolOutputCollection,
)
-LEGACY_DATA_INPUT: Dict[str, Any] = {
+LEGACY_DATA_INPUT: dict[str, Any] = {
"type": "data",
"name": "input",
"format": ["data"],
@@ -32,7 +31,7 @@ LEGACY_DATA_INPUT: Dict[str, Any] = {
"extensions": ["data"],
}
-LEGACY_TEXT_INPUT: Dict[str, Any] = {
+LEGACY_TEXT_INPUT: dict[str, Any] = {
"type": "text",
"name": "msg",
"value": "hello",
@@ -43,7 +42,7 @@ LEGACY_TEXT_INPUT: Dict[str, Any] = {
"default_options": [],
}
-BASE_TOOL: Dict[str, Any] = {
+BASE_TOOL: dict[str, Any] = {
"class": "GalaxyUserTool",
"id": "legacy-tool",
"name": "Legacy",
@@ -154,7 +153,7 @@ def test_lift_does_not_mutate_input():
assert original["inputs"][1] == snapshot["inputs"][1]
-LEGACY_NESTED_COLLECTION_OUTPUT: Dict[str, Any] = {
+LEGACY_NESTED_COLLECTION_OUTPUT: dict[str, Any] = {
"type": "collection",
"name": "outs",
"label": None,
diff --git a/test/unit/util/test_config_template_validation.py b/test/unit/util/test_config_template_validation.py
index 92944a814ef..80802ec2615 100644
--- a/test/unit/util/test_config_template_validation.py
+++ b/test/unit/util/test_config_template_validation.py
@@ -1,8 +1,5 @@
from typing import (
Any,
- Dict,
- List,
- Optional,
)
from galaxy.exceptions import (
@@ -34,9 +31,9 @@ class TestTemplate(StrictModel):
id: str
type: str = "test"
version: int
- variables: Optional[List[TemplateVariable]]
- secrets: Optional[List[TemplateSecret]]
- environment: Optional[List[TemplateEnvironmentEntry]]
+ variables: list[TemplateVariable] | None
+ secrets: list[TemplateSecret] | None
+ environment: list[TemplateEnvironmentEntry] | None
def _template_with_variable(variable: TemplateVariable) -> TestTemplate:
@@ -63,11 +60,11 @@ def _template_with_secret(name: str) -> TestTemplate:
class TestInstanceDefinition(StrictModel):
template_id: str
template_version: int
- variables: Dict[str, Any]
- secrets: Dict[str, str]
+ variables: dict[str, Any]
+ secrets: dict[str, str]
-def _test_instance_with_variables(variables: Dict[str, Any]) -> TestInstanceDefinition:
+def _test_instance_with_variables(variables: dict[str, Any]) -> TestInstanceDefinition:
return TestInstanceDefinition(
template_id=TEST_TEMPLATE_ID,
template_version=TEST_TEMPLATE_VERSION,
@@ -76,7 +73,7 @@ def _test_instance_with_variables(variables: Dict[str, Any]) -> TestInstanceDefi
)
-def _test_instance_with_secrets(secrets: Dict[str, str]) -> TestInstanceDefinition:
+def _test_instance_with_secrets(secrets: dict[str, str]) -> TestInstanceDefinition:
return TestInstanceDefinition(
template_id=TEST_TEMPLATE_ID,
template_version=TEST_TEMPLATE_VERSION,
diff --git a/test/unit/util/test_requests.py b/test/unit/util/test_requests.py
index 910f4c5225e..cbaf316d779 100644
--- a/test/unit/util/test_requests.py
+++ b/test/unit/util/test_requests.py
@@ -79,7 +79,7 @@ def connection_reset_server():
while not stop.is_set():
try:
conn, _ = sock.accept()
- except socket.timeout: # noqa: UP041 # Python <=3.9 support, replace with TimeoutError in Python 3.10+
+ except TimeoutError:
continue
except OSError:
break
diff --git a/test/unit/util/test_utils.py b/test/unit/util/test_utils.py
index 5aebac17e4b..b0287f037c9 100644
--- a/test/unit/util/test_utils.py
+++ b/test/unit/util/test_utils.py
@@ -4,7 +4,6 @@ import tempfile
from enum import Enum
from io import StringIO
from pathlib import Path
-from typing import Dict
import pytest
@@ -92,7 +91,7 @@ def test_iter_start_of_lines():
def test_safe_loads():
- d: Dict[str, str] = {}
+ d: dict[str, str] = {}
rval = safe_loads(d)
assert rval == d
assert rval is not d
diff --git a/test/unit/webapps/api/test_cbv.py b/test/unit/webapps/api/test_cbv.py
index 276a4305040..ce4073dded4 100644
--- a/test/unit/webapps/api/test_cbv.py
+++ b/test/unit/webapps/api/test_cbv.py
@@ -6,7 +6,6 @@ https://github.com/dmontagu/fastapi-utils
from typing import (
Any,
ClassVar,
- Optional,
)
from fastapi import (
@@ -85,7 +84,7 @@ def test_multiple_decorators() -> None:
@router.get("/items/?")
@router.get("/items/{item_path:path}")
@router.get("/database/{item_path:path}")
- def root(self, item_path: Optional[str] = None, item_query: Optional[str] = None) -> Any:
+ def root(self, item_path: str | None = None, item_query: str | None = None) -> Any:
if item_path:
return {"item_path": item_path}
if item_query:
diff --git a/test/unit/webapps/test_client_disconnect.py b/test/unit/webapps/test_client_disconnect.py
index 31252f46951..de0e9748d02 100644
--- a/test/unit/webapps/test_client_disconnect.py
+++ b/test/unit/webapps/test_client_disconnect.py
@@ -2,7 +2,6 @@ import asyncio
import contextlib
import threading
import time
-from typing import Optional
import pytest
import requests
@@ -14,7 +13,7 @@ from starlette.middleware.base import BaseHTTPMiddleware
from galaxy.util import sockets
-error_encountered: Optional[str] = None
+error_encountered: str | None = None
@pytest.fixture()
diff --git a/test/unit/webapps/test_webapp_base.py b/test/unit/webapps/test_webapp_base.py
index f304b3a42ad..c7562d97155 100644
--- a/test/unit/webapps/test_webapp_base.py
+++ b/test/unit/webapps/test_webapp_base.py
@@ -1,4 +1,4 @@
-"""
+"""
Unit tests for ``galaxy.web.framework.webapp``
"""
@@ -6,7 +6,6 @@ import logging
import re
from typing import (
cast,
- Optional,
)
import galaxy.config
@@ -37,7 +36,7 @@ class CORSParsingMockConfig(galaxy_mock.MockAppConfig):
class TestGalaxyWebTransactionHeaders:
- def _new_trans(self, allowed_origin_hostnames: Optional[str] = None) -> StubGalaxyWebTransaction:
+ def _new_trans(self, allowed_origin_hostnames: str | None = None) -> StubGalaxyWebTransaction:
app = cast(BasicSharedApp, galaxy_mock.MockApp())
app.config = CORSParsingMockConfig(allowed_origin_hostnames=allowed_origin_hostnames)
webapp = cast(WebApplication, galaxy_mock.MockWebapp(app.security))
diff --git a/test/unit/workflows/test_modules.py b/test/unit/workflows/test_modules.py
index c56094ff9b9..41efb2f1250 100644
--- a/test/unit/workflows/test_modules.py
+++ b/test/unit/workflows/test_modules.py
@@ -2,8 +2,6 @@ import json
from typing import (
Any,
NamedTuple,
- Optional,
- Union,
)
from unittest import mock
@@ -319,9 +317,9 @@ def test_to_cwl_dataset_collection_element():
class MapOverTestCase(NamedTuple):
data_input: str
- step_input_def: Union[str, list[str]]
+ step_input_def: str | list[str]
step_output_def: str
- expected_collection_type: Optional[str]
+ expected_collection_type: str | None
steps: dict[int, Any]
@@ -333,7 +331,7 @@ def _construct_steps_for_map_over() -> list[MapOverTestCase]:
# step_output_definition = ['dataset', 'list', 'list:list']
# list(itertools.product(data_input, step_input_definition, step_output_definition, [None])),
# with the last item filled in manually
- test_case_args: list[tuple[str, Union[str, list[str]], str, Optional[str]]] = [
+ test_case_args: list[tuple[str, str | list[str], str, str | None]] = [
("dataset", "dataset", "dataset", None),
("dataset", "dataset", "list", "list"),
("dataset", "dataset", "list:list", "list:list"),
diff --git a/tools/data_export/export_remote.py b/tools/data_export/export_remote.py
index f0b027e5a92..8700cf84a91 100644
--- a/tools/data_export/export_remote.py
+++ b/tools/data_export/export_remote.py
@@ -38,7 +38,7 @@ def write_if_not_exists(file_sources, target_uri, real_data_path):
def get_directory_uri(args):
directory_uri = args.directory_uri
if not directory_uri:
- inputs = json.load(open(args.inputs, "r"))
+ inputs = json.load(open(args.inputs))
directory_uri = inputs["d_uri"]
if not directory_uri.endswith("/"):
directory_uri = f"{directory_uri}/"
diff --git a/tools/data_source/data_source.py b/tools/data_source/data_source.py
index ad9d2fa25ce..2185d4b3b1c 100644
--- a/tools/data_source/data_source.py
+++ b/tools/data_source/data_source.py
@@ -49,7 +49,7 @@ def __main__():
for data_dict in params["output_data"]:
cur_filename = data_dict["file_name"]
- cur_URL = params["param_dict"].get("%s|%s|URL" % (GALAXY_PARAM_PREFIX, data_dict["out_data_name"]), URL)
+ cur_URL = params["param_dict"].get("{}|{}|URL".format(GALAXY_PARAM_PREFIX, data_dict["out_data_name"]), URL)
if not cur_URL or urlparse(cur_URL).scheme not in ("http", "https", "ftp"):
open(cur_filename, "w").write("")
sys.exit("The remote data source application has not sent back a URL parameter in the request.")
@@ -82,7 +82,7 @@ def __main__():
source_encoding=get_charset_from_http_headers(page.headers),
)
except Exception as e:
- sys.exit("Unable to fetch %s:\n%s" % (cur_URL, e))
+ sys.exit(f"Unable to fetch {cur_URL}:\n{e}")
# here import checks that upload tool performs
try:
diff --git a/tools/data_source/upload.py b/tools/data_source/upload.py
index a3b5c8089d3..cb8b0d051f4 100644
--- a/tools/data_source/upload.py
+++ b/tools/data_source/upload.py
@@ -3,7 +3,6 @@
# WARNING: Changes in this tool (particularly as related to parsing) may need
# to be reflected in galaxy.web.controllers.tool_runner and galaxy.tools
-from __future__ import print_function
import errno
import os
@@ -14,7 +13,6 @@ from json import (
load,
loads,
)
-from typing import Dict
from galaxy.datatypes import sniff
from galaxy.datatypes.registry import Registry
@@ -82,7 +80,7 @@ def parse_outputs(args):
return rval
-def add_file(dataset, registry, output_path: str) -> Dict[str, str]:
+def add_file(dataset, registry, output_path: str) -> dict[str, str]:
ext = None
line_count = None
link_data_only_str = dataset.get("link_data_only", "copy_files")
@@ -128,7 +126,7 @@ def add_file(dataset, registry, output_path: str) -> Dict[str, str]:
try:
dataset.path = sniff.stream_url_to_file(dataset.path, file_sources=get_file_sources())
except Exception as e:
- raise UploadProblemException("Unable to fetch %s\n%s" % (dataset.path, unicodify(e)))
+ raise UploadProblemException(f"Unable to fetch {dataset.path}\n{unicodify(e)}")
# See if we have an empty file
if not os.path.exists(dataset.path):
@@ -203,7 +201,7 @@ def add_composite_file(dataset, registry, output_path, files_path):
try:
temp_name = sniff.stream_url_to_file(path_or_url, file_sources=file_sources)
except Exception as e:
- raise UploadProblemException("Unable to fetch %s\n%s" % (path_or_url, unicodify(e)))
+ raise UploadProblemException(f"Unable to fetch {path_or_url}\n{unicodify(e)}")
return temp_name, isa_url
@@ -248,9 +246,7 @@ def add_composite_file(dataset, registry, output_path, files_path):
for name, value in dataset.composite_files.items():
value = bunch.Bunch(**value)
if value.name not in dataset.composite_file_paths:
- raise UploadProblemException(
- "Failed to find file_path %s in %s" % (value.name, dataset.composite_file_paths)
- )
+ raise UploadProblemException(f"Failed to find file_path {value.name} in {dataset.composite_file_paths}")
if dataset.composite_file_paths[value.name] is None and not value.optional:
raise UploadProblemException("A required composite data file was not provided (%s)" % name)
elif dataset.composite_file_paths[value.name] is not None: