Skip to content

refactor: add proper return types to resource sequence methods #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/connect/databricks/fastapi/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from __future__ import annotations

import os
from typing import TYPE_CHECKING, Annotated

from databricks import sql
from databricks.sdk.core import Config, databricks_cli
from fastapi import FastAPI, Header
from typing_extensions import TYPE_CHECKING, Annotated

from posit.connect.external.databricks import PositCredentialsStrategy

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from __future__ import annotations

from typing import TYPE_CHECKING

import pytest
from typing_extensions import TYPE_CHECKING

from posit import connect

Expand Down
3 changes: 2 additions & 1 deletion src/posit/connect/_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from __future__ import annotations

from collections.abc import Mapping
from typing import TYPE_CHECKING, Any, Optional, cast

from typing_extensions import TYPE_CHECKING, Any, Optional, cast

from ._api_call import ApiCallMixin, get_api
from ._json import Jsonifiable, JsonifiableDict, ResponseAttrs
Expand Down
3 changes: 2 additions & 1 deletion src/posit/connect/_api_call.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import annotations

import posixpath
from typing import TYPE_CHECKING, Protocol

from typing_extensions import TYPE_CHECKING, Protocol

if TYPE_CHECKING:
from ._json import Jsonifiable
Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/_json.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Tuple, TypeVar, Union
from typing_extensions import Dict, List, Tuple, TypeVar, Union

# Implemented in https://github.com/posit-dev/py-shiny/blob/415ced034e6c500adda524abb7579731c32088b5/shiny/types.py#L357-L386
# Table from: https://github.com/python/cpython/blob/df1eec3dae3b1eddff819fd70f58b03b3fbd0eda/Lib/json/encoder.py#L77-L95
Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Any
from typing_extensions import Any


def drop_none(x: dict[str, Any]) -> dict[str, Any]:
Expand Down
7 changes: 4 additions & 3 deletions src/posit/connect/bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@
from __future__ import annotations

import io
from typing import TYPE_CHECKING, List

from typing_extensions import TYPE_CHECKING, List

from . import resources, tasks

if TYPE_CHECKING:
from .context import Context


class BundleMetadata(resources.Resource):
class BundleMetadata(resources.BaseResource):
pass


class Bundle(resources.Resource):
class Bundle(resources.BaseResource):
@property
def metadata(self) -> BundleMetadata:
return BundleMetadata(self._ctx, **self.get("metadata", {}))
Expand Down
10 changes: 6 additions & 4 deletions src/posit/connect/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

from __future__ import annotations

from typing import TYPE_CHECKING, overload

from requests import Response, Session
from typing_extensions import TYPE_CHECKING, overload

from posit.connect.environments import Environment
from posit.connect.packages import Package

from . import hooks, me
from .auth import Auth
Expand Down Expand Up @@ -299,7 +301,7 @@ def oauth(self) -> OAuth:
@property
@requires(version="2024.11.0")
def packages(self) -> Packages:
return _PaginatedResourceSequence(self._ctx, "v1/packages", uid="name")
return _PaginatedResourceSequence[Package](self._ctx, "v1/packages", uid="name")

@property
def vanities(self) -> Vanities:
Expand All @@ -312,7 +314,7 @@ def system(self) -> System:
@property
@requires(version="2023.05.0")
def environments(self) -> Environments:
return _ResourceSequence(self._ctx, "v1/environments")
return _ResourceSequence[Environment](self._ctx, "v1/environments")

def __del__(self):
"""Close the session when the Client instance is deleted."""
Expand Down
3 changes: 2 additions & 1 deletion src/posit/connect/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Client configuration."""

import os
from typing import Optional

from typing_extensions import Optional

from . import urls

Expand Down
19 changes: 11 additions & 8 deletions src/posit/connect/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@

import posixpath
import time
from typing import (

from typing_extensions import (
TYPE_CHECKING,
Any,
List,
Literal,
NotRequired,
Optional,
Required,
TypedDict,
Unpack,
cast,
overload,
)

from typing_extensions import NotRequired, Required, TypedDict, Unpack

from . import tasks
from ._api import ApiDictEndpoint, JsonifiableDict
from .bundles import Bundles
Expand All @@ -24,7 +27,7 @@
from .errors import ClientError
from .oauth.associations import ContentItemAssociations
from .permissions import Permissions
from .resources import Active, Resource, Resources, _ResourceSequence
from .resources import Active, BaseResource, Resources, _ResourceSequence
from .tags import ContentItemTags
from .vanities import VanityMixin
from .variants import Variants
Expand Down Expand Up @@ -160,7 +163,7 @@ def update(
)


class ContentItemOAuth(Resource):
class ContentItemOAuth(BaseResource):
def __init__(self, ctx: Context, content_guid: str) -> None:
super().__init__(ctx)
self["content_guid"] = content_guid
Expand All @@ -170,11 +173,11 @@ def associations(self) -> ContentItemAssociations:
return ContentItemAssociations(self._ctx, content_guid=self["content_guid"])


class ContentItemOwner(Resource):
class ContentItemOwner(BaseResource):
pass


class ContentItem(Active, VanityMixin, Resource):
class ContentItem(Active, VanityMixin, BaseResource):
class _AttrsBase(TypedDict, total=False):
# # `name` will be set by other _Attrs classes
# name: str
Expand Down Expand Up @@ -376,7 +379,7 @@ def restart(self) -> None:
f"Restart not supported for this application mode: {self['app_mode']}. Did you need to use the 'render()' method instead? Note that some application modes do not support 'render()' or 'restart()'.",
)

def update(
def update( # type: ignore[reportIncompatibleMethodOverride]
self,
**attrs: Unpack[ContentItem._Attrs],
) -> None:
Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import functools
import weakref
from typing import TYPE_CHECKING, Protocol

from packaging.version import Version
from typing_extensions import TYPE_CHECKING, Protocol

if TYPE_CHECKING:
from .client import Client
Expand Down
3 changes: 2 additions & 1 deletion src/posit/connect/cursors.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Generator, List

from typing_extensions import TYPE_CHECKING, Any, Generator, List

if TYPE_CHECKING:
from .context import Context
Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/env.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Any, Iterator, List, Mapping, MutableMapping, Optional
from typing_extensions import TYPE_CHECKING, Any, Iterator, List, Mapping, MutableMapping, Optional

from .resources import Resources

Expand Down
17 changes: 4 additions & 13 deletions src/posit/connect/environments.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
from __future__ import annotations

from abc import abstractmethod
from collections.abc import Mapping, Sized

from typing_extensions import (
Any,
List,
Literal,
Protocol,
SupportsIndex,
TypedDict,
overload,
runtime_checkable,
)

from .resources import Resource, ResourceSequence

MatchingType = Literal["any", "exact", "none"]
"""Directions for how environments are considered for selection.

Expand All @@ -40,7 +38,7 @@ class Installations(TypedDict):
"""Interpreter installations in an execution environment."""


class Environment(Mapping[str, Any]):
class Environment(Resource):
@abstractmethod
def destroy(self) -> None:
"""Destroy the environment.
Expand Down Expand Up @@ -95,13 +93,7 @@ def update(


@runtime_checkable
class Environments(Sized, Protocol):
@overload
def __getitem__(self, index: SupportsIndex) -> Environment: ...

@overload
def __getitem__(self, index: slice) -> List[Environment]: ...

class Environments(ResourceSequence[Environment], Protocol):
def create(
self,
*,
Expand Down Expand Up @@ -217,4 +209,3 @@ def find_by(
----
This action requires administrator or publisher privileges.
"""
...
3 changes: 2 additions & 1 deletion src/posit/connect/errors.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
from typing import Any

from typing_extensions import Any


class ClientError(Exception):
Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/external/databricks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
"""

import abc
from typing import Callable, Dict, Optional

import requests
from typing_extensions import Callable, Dict, Optional

from ..client import Client
from ..oauth import Credentials
Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/external/snowflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
NOTE: The APIs in this module are provided as a convenience and are subject to breaking changes.
"""

from typing import Optional
from typing_extensions import Optional

from ..client import Client
from .external import is_local
Expand Down
6 changes: 3 additions & 3 deletions src/posit/connect/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from __future__ import annotations

from typing import TYPE_CHECKING, List, Optional, overload
from typing_extensions import TYPE_CHECKING, List, Optional, overload

from .paginator import Paginator
from .resources import Resource, Resources
from .resources import BaseResource, Resources

if TYPE_CHECKING:
import requests
Expand All @@ -14,7 +14,7 @@
from .users import User


class Group(Resource):
class Group(BaseResource):
def __init__(self, ctx: Context, **kwargs) -> None:
super().__init__(ctx, **kwargs)
self._ctx: Context = ctx
Expand Down
22 changes: 6 additions & 16 deletions src/posit/connect/jobs.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
from __future__ import annotations

from abc import abstractmethod
from collections.abc import Mapping, Sized
from typing import (
Any,
from typing_extensions import (
Iterable,
List,
Literal,
Protocol,
SupportsIndex,
overload,
runtime_checkable,
)

from .resources import Resource, ResourceSequence

JobTag = Literal[
"unknown",
"build_report",
Expand Down Expand Up @@ -43,8 +39,8 @@
StatusCode = Literal[0, 1, 2]


class Job(Mapping[str, Any]):
@abstractmethod
@runtime_checkable
class Job(Resource, Protocol):
def destroy(self) -> None:
"""Destroy the job.

Expand All @@ -59,13 +55,7 @@ def destroy(self) -> None:


@runtime_checkable
class Jobs(Sized, Protocol):
@overload
def __getitem__(self, index: SupportsIndex) -> Job: ...

@overload
def __getitem__(self, index: slice) -> List[Job]: ...

class Jobs(ResourceSequence[Job], Protocol):
def fetch(self) -> Iterable[Job]:
"""Fetch all jobs.

Expand Down
6 changes: 3 additions & 3 deletions src/posit/connect/metrics/shiny_usage.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from __future__ import annotations

from typing import List, overload
from typing_extensions import List, overload

from ..cursors import CursorPaginator
from ..resources import Resource, Resources
from ..resources import BaseResource, Resources


class ShinyUsageEvent(Resource):
class ShinyUsageEvent(BaseResource):
@property
def content_guid(self) -> str:
"""The associated unique content identifier.
Expand Down
Loading
Loading