From 03f39a15163f7a6a7595a44ab835144199390f48 Mon Sep 17 00:00:00 2001 From: Jesse Vickery Date: Thu, 5 Nov 2026 14:05:27 -0500 Subject: [PATCH 1/4] feat(dev): typing; - Added type classes. --- ckan/types/logic/action_result.py | 163 +++++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 2 deletions(-) diff --git a/ckan/types/logic/action_result.py b/ckan/types/logic/action_result.py index 643ed6c5e1d..cd9071bd579 100644 --- a/ckan/types/logic/action_result.py +++ b/ckan/types/logic/action_result.py @@ -1,10 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import annotations +# (canada fork only): TypedDict sub-classes for action results +# TODO: upstream contrib!!! from typing import ( - Any, List, Optional, Tuple, Union + Any, List, Optional, Tuple, Union, Dict, Any ) -from typing_extensions import TypeAlias +# (canada fork only): TypedDict sub-classes for action results +# TODO: upstream contrib!!! +from typing_extensions import TypeAlias, TypedDict, Required +# (canada fork only): TypedDict sub-classes for action results +# TODO: upstream contrib!!! +from sqlalchemy.types import DateTime from ..model import Query, Model @@ -79,6 +86,158 @@ JobShow = AnyDict ApiTokenList = List[AnyDict] +# (canada fork only): TypedDict sub-classes for action results +# TODO: upstream contrib!!! +class ExtrasDict(TypedDict, total=False): + ''' + Dictionary for object extras. + + see: ckan.logic.schema.default_tags_schema + ''' + id: str + key: Required[str] + value: Required[Any] + state: str + deleted: bool + revision_timestamp: DateTime + + +class TagDict(TypedDict, total=False): + ''' + Dictionary for tags. + + see: ckan.logic.schema.default_tags_schema + ''' + name: Required[str] + vocabulary_id: str + revision_timestamp: DateTime + state: str + display_name: str + + +class TrackingSummaryDict(TypedDict): + ''' + Dictionary for tracking summaries. + + see: ckan.model.tracking:TrackingSummary + ''' + total: int + recent: int + + +class ResourceShowDict(TypedDict, total=False): + ''' + Dictionary returned from the resource_show action. + + see: ckan.logic.schema.default_show_package_schema + ''' + id: Required[str] + package_id: Required[str] + url: str + description: str + format: str + hash: str + state: str + position: int + name: str + resource_type: str + url_type: str + mimetype: str + mimetype_inner: str + cache_url: str + size: int + created: Required[DateTime] + last_modified: DateTime + metadata_modified: DateTime + cache_last_updated: DateTime + datastore_active: bool + tracking_summary: TrackingSummaryDict + + +class PackageShowDict(TypedDict, total=False): + ''' + Dictionary returned from the package_show action. + + see: ckan.logic.schema.default_show_package_schema + ''' + id: Required[str] + name: Optional[str] + title: str + notes: str + type: str + url: str + version: str + metadata_created: Required[DateTime] + metadata_modified: DateTime + plugin_data: Dict[str, Any] + private: bool + state: str + isopen: bool + license_url: str + creator_user_id: str + author: str + author_email: str + maintainer: str + maintainer_email: str + license_id: str + license_title: str + tracking_summary: TrackingSummaryDict + owner_org: str + organization: OrganizationShowDict + resources: List[ResourceShowDict] + num_resources: int + tags: List[TagDict] + tag_string: str + num_tags: int + + +class GroupPackageDict(TypedDict, total=False): + ''' + Dictionary part of a group's packages. + + see: ckan.logic.schema.default_group_schema + ''' + id: Required[str] + title: str + name: str + + +class GroupMemberDict(TypedDict, total=False): + ''' + Dictionary part of a group's users and groups. + + see: ckan.logic.schema.default_group_schema + ''' + name: Required[str] + capacity: str + + +class OrganizationShowDict(TypedDict, total=False): + ''' + Dictionary returned from the organization_show action. + + see: ckan.logic.schema.default_show_group_schema + ''' + id: Required[str] + name: Required[str] + title: str + description: str + image_url: str + image_display_url: str + type: str + state: str + created: DateTime + is_organization: bool + approval_status: str + extras: List[ExtrasDict] + packages: List[GroupPackageDict] + users: List[GroupMemberDict] + groups: List[GroupMemberDict] + num_followers: int + display_name: str + package_count: int + + ############################################################################### # create # ############################################################################### From fba56da694560d2302b6c84acfbfa00524bb4332 Mon Sep 17 00:00:00 2001 From: Jesse Vickery Date: Thu, 5 Nov 2026 14:25:34 -0500 Subject: [PATCH 2/4] feat(misc): changelog; - Added change log file. --- changes/240.canada.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/240.canada.feature diff --git a/changes/240.canada.feature b/changes/240.canada.feature new file mode 100644 index 00000000000..4ad513b1c49 --- /dev/null +++ b/changes/240.canada.feature @@ -0,0 +1 @@ +Added `TypedDict` sub-classes for `package_show`, `resource_show`, and `organization_show` to help improve code type checking. From 4de8a85b0b3e4db87b5ef1ba6211b17a24c4cc28 Mon Sep 17 00:00:00 2001 From: Jesse Vickery Date: Fri, 6 Nov 2026 14:29:53 -0500 Subject: [PATCH 3/4] feat(misc): changelog; - Added change log file. --- ckan/types/__init__.py | 163 ++++++++++++++++++++++++++++++ ckan/types/logic/action_result.py | 163 +----------------------------- 2 files changed, 165 insertions(+), 161 deletions(-) diff --git a/ckan/types/__init__.py b/ckan/types/__init__.py index 779acf85b13..70066e68848 100644 --- a/ckan/types/__init__.py +++ b/ckan/types/__init__.py @@ -26,6 +26,12 @@ if TYPE_CHECKING: from ckanext.activity.model import Activity +# (canada fork only): TypedDict sub-classes for action results +# TODO: upstream contrib!!! +from sqlalchemy.types import DateTime +from typing_extensions import Required +from typing import Dict, List + __all__ = [ "Response", "Request", @@ -41,6 +47,11 @@ "AuthResult", "Action", "ChainedAction", "AuthFunction", "ChainedAuthFunction", "PFeed", "PFeedFactory", "PResourceUploader", "PUploader", + # (canada fork only): TypedDict sub-classes for action results + # TODO: upstream contrib!!! + 'ExtrasDict', 'TagDict', 'TrackingSummaryDict', + 'ResourceShowDict', 'PackageShowDict', 'GroupPackageDict', + 'GroupMemberDict', 'OrganizationShowDict' ] Config: TypeAlias = Dict[str, Union[str, Mapping[str, str]]] CKANApp = Any @@ -242,3 +253,155 @@ def get_path(self, id: str) -> str: def upload(self, id: str, max_size: int = ...) -> None: ... + + +# (canada fork only): TypedDict sub-classes for action results +# TODO: upstream contrib!!! +class ExtrasDict(TypedDict, total=False): + ''' + Dictionary for object extras. + + see: ckan.logic.schema.default_tags_schema + ''' + id: str + key: Required[str] + value: Required[Any] + state: str + deleted: bool + revision_timestamp: DateTime + + +class TagDict(TypedDict, total=False): + ''' + Dictionary for tags. + + see: ckan.logic.schema.default_tags_schema + ''' + name: Required[str] + vocabulary_id: str + revision_timestamp: DateTime + state: str + display_name: str + + +class TrackingSummaryDict(TypedDict): + ''' + Dictionary for tracking summaries. + + see: ckan.model.tracking:TrackingSummary + ''' + total: int + recent: int + + +class ResourceShowDict(TypedDict, total=False): + ''' + Dictionary returned from the resource_show action. + + see: ckan.logic.schema.default_show_package_schema + ''' + id: Required[str] + package_id: Required[str] + url: str + description: str + format: str + hash: str + state: str + position: int + name: str + resource_type: str + url_type: str + mimetype: str + mimetype_inner: str + cache_url: str + size: int + created: Required[DateTime] + last_modified: DateTime + metadata_modified: DateTime + cache_last_updated: DateTime + datastore_active: bool + tracking_summary: TrackingSummaryDict + + +class PackageShowDict(TypedDict, total=False): + ''' + Dictionary returned from the package_show action. + + see: ckan.logic.schema.default_show_package_schema + ''' + id: Required[str] + name: Optional[str] + title: str + notes: str + type: str + url: str + version: str + metadata_created: Required[DateTime] + metadata_modified: DateTime + plugin_data: Dict[str, Any] + private: bool + state: str + isopen: bool + license_url: str + creator_user_id: str + author: str + author_email: str + maintainer: str + maintainer_email: str + license_id: str + license_title: str + tracking_summary: TrackingSummaryDict + owner_org: str + organization: OrganizationShowDict + resources: List[ResourceShowDict] + num_resources: int + tags: List[TagDict] + tag_string: str + num_tags: int + + +class GroupPackageDict(TypedDict, total=False): + ''' + Dictionary part of a group's packages. + + see: ckan.logic.schema.default_group_schema + ''' + id: Required[str] + title: str + name: str + + +class GroupMemberDict(TypedDict, total=False): + ''' + Dictionary part of a group's users and groups. + + see: ckan.logic.schema.default_group_schema + ''' + name: Required[str] + capacity: str + + +class OrganizationShowDict(TypedDict, total=False): + ''' + Dictionary returned from the organization_show action. + + see: ckan.logic.schema.default_show_group_schema + ''' + id: Required[str] + name: Required[str] + title: str + description: str + image_url: str + image_display_url: str + type: str + state: str + created: DateTime + is_organization: bool + approval_status: str + extras: List[ExtrasDict] + packages: List[GroupPackageDict] + users: List[GroupMemberDict] + groups: List[GroupMemberDict] + num_followers: int + display_name: str + package_count: int diff --git a/ckan/types/logic/action_result.py b/ckan/types/logic/action_result.py index cd9071bd579..b06d8343d91 100644 --- a/ckan/types/logic/action_result.py +++ b/ckan/types/logic/action_result.py @@ -1,17 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import annotations -# (canada fork only): TypedDict sub-classes for action results -# TODO: upstream contrib!!! from typing import ( - Any, List, Optional, Tuple, Union, Dict, Any + Any, List, Optional, Tuple, Union, Any ) -# (canada fork only): TypedDict sub-classes for action results -# TODO: upstream contrib!!! -from typing_extensions import TypeAlias, TypedDict, Required -# (canada fork only): TypedDict sub-classes for action results -# TODO: upstream contrib!!! -from sqlalchemy.types import DateTime +from typing_extensions import TypeAlias from ..model import Query, Model @@ -86,158 +79,6 @@ JobShow = AnyDict ApiTokenList = List[AnyDict] -# (canada fork only): TypedDict sub-classes for action results -# TODO: upstream contrib!!! -class ExtrasDict(TypedDict, total=False): - ''' - Dictionary for object extras. - - see: ckan.logic.schema.default_tags_schema - ''' - id: str - key: Required[str] - value: Required[Any] - state: str - deleted: bool - revision_timestamp: DateTime - - -class TagDict(TypedDict, total=False): - ''' - Dictionary for tags. - - see: ckan.logic.schema.default_tags_schema - ''' - name: Required[str] - vocabulary_id: str - revision_timestamp: DateTime - state: str - display_name: str - - -class TrackingSummaryDict(TypedDict): - ''' - Dictionary for tracking summaries. - - see: ckan.model.tracking:TrackingSummary - ''' - total: int - recent: int - - -class ResourceShowDict(TypedDict, total=False): - ''' - Dictionary returned from the resource_show action. - - see: ckan.logic.schema.default_show_package_schema - ''' - id: Required[str] - package_id: Required[str] - url: str - description: str - format: str - hash: str - state: str - position: int - name: str - resource_type: str - url_type: str - mimetype: str - mimetype_inner: str - cache_url: str - size: int - created: Required[DateTime] - last_modified: DateTime - metadata_modified: DateTime - cache_last_updated: DateTime - datastore_active: bool - tracking_summary: TrackingSummaryDict - - -class PackageShowDict(TypedDict, total=False): - ''' - Dictionary returned from the package_show action. - - see: ckan.logic.schema.default_show_package_schema - ''' - id: Required[str] - name: Optional[str] - title: str - notes: str - type: str - url: str - version: str - metadata_created: Required[DateTime] - metadata_modified: DateTime - plugin_data: Dict[str, Any] - private: bool - state: str - isopen: bool - license_url: str - creator_user_id: str - author: str - author_email: str - maintainer: str - maintainer_email: str - license_id: str - license_title: str - tracking_summary: TrackingSummaryDict - owner_org: str - organization: OrganizationShowDict - resources: List[ResourceShowDict] - num_resources: int - tags: List[TagDict] - tag_string: str - num_tags: int - - -class GroupPackageDict(TypedDict, total=False): - ''' - Dictionary part of a group's packages. - - see: ckan.logic.schema.default_group_schema - ''' - id: Required[str] - title: str - name: str - - -class GroupMemberDict(TypedDict, total=False): - ''' - Dictionary part of a group's users and groups. - - see: ckan.logic.schema.default_group_schema - ''' - name: Required[str] - capacity: str - - -class OrganizationShowDict(TypedDict, total=False): - ''' - Dictionary returned from the organization_show action. - - see: ckan.logic.schema.default_show_group_schema - ''' - id: Required[str] - name: Required[str] - title: str - description: str - image_url: str - image_display_url: str - type: str - state: str - created: DateTime - is_organization: bool - approval_status: str - extras: List[ExtrasDict] - packages: List[GroupPackageDict] - users: List[GroupMemberDict] - groups: List[GroupMemberDict] - num_followers: int - display_name: str - package_count: int - - ############################################################################### # create # ############################################################################### From 025e31b62394b3b45b4aa62e956544bcd0edd45b Mon Sep 17 00:00:00 2001 From: Jesse Vickery Date: Fri, 6 Nov 2026 14:30:59 -0500 Subject: [PATCH 4/4] feat(misc): changelog; - Added change log file. --- ckan/types/logic/action_result.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ckan/types/logic/action_result.py b/ckan/types/logic/action_result.py index b06d8343d91..643ed6c5e1d 100644 --- a/ckan/types/logic/action_result.py +++ b/ckan/types/logic/action_result.py @@ -2,7 +2,7 @@ from __future__ import annotations from typing import ( - Any, List, Optional, Tuple, Union, Any + Any, List, Optional, Tuple, Union ) from typing_extensions import TypeAlias