diff --git a/lib/tool_shed/metadata/repository_metadata_manager.py b/lib/tool_shed/metadata/repository_metadata_manager.py index b475d56a41c..021345fdc77 100644 --- a/lib/tool_shed/metadata/repository_metadata_manager.py +++ b/lib/tool_shed/metadata/repository_metadata_manager.py @@ -1087,7 +1087,7 @@ def get_repository_metadata(session, repository_id): stmt = ( select(RepositoryMetadata) .where(RepositoryMetadata.repository_id == repository_id) - .order_by(RepositoryMetadata.changeset_revision, RepositoryMetadata.update_time.desc()) # type: ignore[attr-defined] # mapped attribute + .order_by(RepositoryMetadata.changeset_revision, RepositoryMetadata.update_time.desc()) ) return session.scalars(stmt) diff --git a/lib/tool_shed/webapp/model/__init__.py b/lib/tool_shed/webapp/model/__init__.py index 0b44c33630e..8dbacb9a064 100644 --- a/lib/tool_shed/webapp/model/__init__.py +++ b/lib/tool_shed/webapp/model/__init__.py @@ -387,13 +387,14 @@ class Repository(Base, Dictifiable): user = relationship("User", back_populates="active_repositories") downloadable_revisions = relationship( "RepositoryMetadata", - primaryjoin=lambda: (Repository.id == RepositoryMetadata.repository_id) & (RepositoryMetadata.downloadable == true()), # type: ignore[has-type] + primaryjoin=lambda: (Repository.id == RepositoryMetadata.repository_id) + & (RepositoryMetadata.downloadable == true()), viewonly=True, - order_by=lambda: desc(RepositoryMetadata.update_time), # type: ignore[attr-defined] + order_by=lambda: desc(RepositoryMetadata.update_time), ) metadata_revisions = relationship( "RepositoryMetadata", - order_by=lambda: desc(RepositoryMetadata.update_time), # type: ignore[attr-defined] + order_by=lambda: desc(RepositoryMetadata.update_time), back_populates="repository", ) roles = relationship("RepositoryRoleAssociation", back_populates="repository") @@ -702,10 +703,26 @@ class Tag(Base): class RepositoryMetadata(Dictifiable): - repository: "Repository" + # 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]] + 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]] + repository: Mapped["Repository"] - # Once the class has been mapped, all Column items in this table will be available - # as instrumented class attributes on RepositoryMetadata. table = Table( "repository_metadata", mapper_registry.metadata, diff --git a/test/unit/tool_shed/test_shed_index.py b/test/unit/tool_shed/test_shed_index.py index a0bdba5fbcd..2d42dd86421 100644 --- a/test/unit/tool_shed/test_shed_index.py +++ b/test/unit/tool_shed/test_shed_index.py @@ -91,12 +91,10 @@ def test_get_repositories_for_indexing_orders_by_last_revision_create_time(shed_ base = datetime(2026, 1, 1, 12, 0, 0) rm_a = RepositoryMetadata(repository_id=repo_a.id, changeset_revision="a", downloadable=True) rm_b = RepositoryMetadata(repository_id=repo_b.id, changeset_revision="b", downloadable=True) - # setattr — RepositoryMetadata is imperatively mapped, so create_time / - # update_time aren't visible to the static type checker. - setattr(rm_a, "create_time", base) - setattr(rm_a, "update_time", base) - setattr(rm_b, "create_time", base + timedelta(hours=1)) - setattr(rm_b, "update_time", base + timedelta(hours=1)) + rm_a.create_time = base + rm_a.update_time = base + rm_b.create_time = base + timedelta(hours=1) + rm_b.update_time = base + timedelta(hours=1) session.add_all([rm_a, rm_b]) # Make repo_a's row look "recently updated" — under the old ORDER BY this # surfaced repo_a first even though repo_b has the newer downloadable