From 863b2470a34a362b8838bcfa5a3396034a91935e Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Wed, 12 Aug 2026 15:34:24 -0700 Subject: [PATCH] feat: Rename SeamMultiWorkspace to SeamWithoutWorkspace --- README.rst | 24 ++++++++++++----- seam/__init__.py | 2 +- seam/auth.py | 2 +- seam/models.py | 4 +-- ...workspace.py => seam_without_workspace.py} | 22 ++++++++-------- test/personal_access_token_test.py | 26 +++++++++---------- 6 files changed, 45 insertions(+), 35 deletions(-) rename seam/{seam_multi_workspace.py => seam_without_workspace.py} (87%) diff --git a/README.rst b/README.rst index 74e42026..d7dc2b76 100644 --- a/README.rst +++ b/README.rst @@ -57,7 +57,9 @@ Contents * `Return all resources across all pages as a list`_ - * `Interacting with Multiple Workspaces`_ + * `Requests without a Workspace in Scope`_ + + * `Personal Access Token without a Workspace`_ * `Webhooks`_ @@ -367,20 +369,28 @@ Return all resources across all pages as a list all_devices = paginator.flatten_to_list() -Interacting with Multiple Workspaces -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Requests without a Workspace in Scope +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Some Seam API endpoints interact with multiple workspaces. The ``SeamMultiWorkspace`` client is not bound to a specific workspace and may use those endpoints with a personal access token authentication method. +Some Seam API endpoints do not require a workspace in scope. +The ``SeamWithoutWorkspace`` client is not bound to a specific workspace +and may use those endpoints with an appropriate authentication method. -A Personal Access Token is scoped to a Seam Console user. Obtain one from the Seam Console. +Personal Access Token without a Workspace +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A Personal Access Token is scoped to a Seam Console user. +Obtain one from the Seam Console. .. code-block:: python + from seam import SeamWithoutWorkspace + # Pass as an option to the constructor - seam = SeamMultiWorkspace(personal_access_token="your-personal-access-token") + seam = SeamWithoutWorkspace(personal_access_token="your-personal-access-token") # Use the factory method - seam = SeamMultiWorkspace.from_personal_access_token("your-personal-access-token") + seam = SeamWithoutWorkspace.from_personal_access_token("your-personal-access-token") # List workspaces authorized for this Personal Access Token workspaces = seam.workspaces.list() diff --git a/seam/__init__.py b/seam/__init__.py index f93f29d1..6e62d98d 100644 --- a/seam/__init__.py +++ b/seam/__init__.py @@ -2,7 +2,7 @@ # type: ignore from .seam import Seam -from .seam_multi_workspace import SeamMultiWorkspace +from .seam_without_workspace import SeamWithoutWorkspace from .options import SeamInvalidOptionsError from .auth import SeamInvalidTokenError from .exceptions import ( diff --git a/seam/auth.py b/seam/auth.py index dff33559..3b30c071 100644 --- a/seam/auth.py +++ b/seam/auth.py @@ -111,7 +111,7 @@ def get_auth_headers_for_personal_access_token( } -def get_auth_headers_for_multi_workspace_personal_access_token( +def get_auth_headers_for_without_workspace_personal_access_token( personal_access_token: str, ) -> dict: if is_jwt(personal_access_token): diff --git a/seam/models.py b/seam/models.py index 2ef8b440..98d96b26 100644 --- a/seam/models.py +++ b/seam/models.py @@ -45,7 +45,7 @@ def from_personal_access_token( raise NotImplementedError -class AbstractSeamMultiWorkspaceWorkspaces(abc.ABC): +class AbstractSeamWithoutWorkspaceWorkspaces(abc.ABC): @abc.abstractmethod def create( self, @@ -65,7 +65,7 @@ def list( raise NotImplementedError() -class AbstractSeamMultiWorkspace: +class AbstractSeamWithoutWorkspace: lts_version: str wait_for_action_attempt: Optional[Union[bool, Dict[str, float]]] diff --git a/seam/seam_multi_workspace.py b/seam/seam_without_workspace.py similarity index 87% rename from seam/seam_multi_workspace.py rename to seam/seam_without_workspace.py index 73b95f92..60be7453 100644 --- a/seam/seam_multi_workspace.py +++ b/seam/seam_without_workspace.py @@ -3,11 +3,11 @@ from typing_extensions import Self from urllib3.util import Retry -from .auth import get_auth_headers_for_multi_workspace_personal_access_token +from .auth import get_auth_headers_for_without_workspace_personal_access_token from .constants import DEFAULT_TIMEOUT, LTS_VERSION from .options import get_endpoint from .client import SeamHttpClient -from .models import AbstractSeamMultiWorkspace +from .models import AbstractSeamWithoutWorkspace from .routes.workspaces import Workspaces @@ -24,7 +24,7 @@ def create(self, **kwargs): return self._workspaces.create(**kwargs) -class SeamMultiWorkspace(AbstractSeamMultiWorkspace): +class SeamWithoutWorkspace(AbstractSeamWithoutWorkspace): """ Seam class used to interact with Seam API without being scoped to a specific workspace. @@ -56,9 +56,9 @@ def __init__( niquests_options: Optional[Dict[str, Any]] = None, ): """ - Initialize a SeamMultiWorkspace client instance. + Initialize a SeamWithoutWorkspace client instance. - This method sets up the SeamMultiWorkspace client with the provided personal access token + This method sets up the SeamWithoutWorkspace client with the provided personal access token and configuration options. :param personal_access_token: A personal access token for @@ -83,9 +83,9 @@ def __init__( :raises SeamInvalidTokenError: If the provided personal access token format is invalid """ - self.lts_version = SeamMultiWorkspace.lts_version + self.lts_version = SeamWithoutWorkspace.lts_version self.wait_for_action_attempt = wait_for_action_attempt - auth_headers = get_auth_headers_for_multi_workspace_personal_access_token( + auth_headers = get_auth_headers_for_without_workspace_personal_access_token( personal_access_token ) endpoint = get_endpoint(endpoint) @@ -115,9 +115,9 @@ def from_personal_access_token( niquests_options: Optional[Dict[str, Any]] = None, ) -> Self: """ - Create a SeamMultiWorkspace instance using a personal access token. + Create a SeamWithoutWorkspace instance using a personal access token. - This class method is a convenience constructor for creating a SeamMultiWorkspace instance + This class method is a convenience constructor for creating a SeamWithoutWorkspace instance authenticated with a personal access token. :param personal_access_token: The personal access token for authenticating with Seam @@ -130,13 +130,13 @@ def from_personal_access_token( :type wait_for_action_attempt: Optional[Union[bool, Dict[str, float]]] :param retries: Configuration for retry behavior on failed requests :type retries: Optional[urllib3.util.Retry] - :return: A new instance of the SeamMultiWorkspace class + :return: A new instance of the SeamWithoutWorkspace class authenticated with the provided personal access token :rtype: Self :Example: - >>> seam = SeamMultiWorkspace.from_personal_access_token("your-personal-access-token-here") + >>> seam = SeamWithoutWorkspace.from_personal_access_token("your-personal-access-token-here") """ return cls( diff --git a/test/personal_access_token_test.py b/test/personal_access_token_test.py index 57ed3100..abb2ad7f 100644 --- a/test/personal_access_token_test.py +++ b/test/personal_access_token_test.py @@ -1,6 +1,6 @@ import pytest -from seam import Seam, SeamMultiWorkspace +from seam import Seam, SeamWithoutWorkspace from seam.auth import SeamInvalidTokenError # UPSTREAM: The fake rejects a personal access token on /devices/list, so these @@ -57,11 +57,11 @@ def test_seam_checks_personal_access_token_format(): Seam.from_personal_access_token("seam_pk_token", workspace_id) -def test_seam_multi_workspace_from_personal_access_token_returns_authorized_instance( +def test_seam_without_workspace_from_personal_access_token_returns_authorized_instance( server, ): endpoint, seed = server - seam = SeamMultiWorkspace.from_personal_access_token( + seam = SeamWithoutWorkspace.from_personal_access_token( seed["seam_at1_token"], endpoint=endpoint ) @@ -70,9 +70,9 @@ def test_seam_multi_workspace_from_personal_access_token_returns_authorized_inst assert len(workspaces) > 0 -def test_seam_multi_workspace_constructor_returns_authorized_instance(server): +def test_seam_without_workspace_constructor_returns_authorized_instance(server): endpoint, seed = server - seam = SeamMultiWorkspace( + seam = SeamWithoutWorkspace( personal_access_token=seed["seam_at1_token"], endpoint=endpoint ) @@ -81,9 +81,9 @@ def test_seam_multi_workspace_constructor_returns_authorized_instance(server): assert len(workspaces) > 0 -def test_seam_multi_workspace_creates_a_workspace(server): +def test_seam_without_workspace_creates_a_workspace(server): endpoint, seed = server - seam = SeamMultiWorkspace( + seam = SeamWithoutWorkspace( personal_access_token=seed["seam_at1_token"], endpoint=endpoint ) @@ -96,18 +96,18 @@ def test_seam_multi_workspace_creates_a_workspace(server): assert workspace.workspace_id is not None -def test_seam_multi_workspace_checks_personal_access_token_format(): +def test_seam_without_workspace_checks_personal_access_token_format(): with pytest.raises(SeamInvalidTokenError, match=r"Unknown"): - SeamMultiWorkspace.from_personal_access_token("some-invalid-key-format") + SeamWithoutWorkspace.from_personal_access_token("some-invalid-key-format") with pytest.raises(SeamInvalidTokenError, match=r"Unknown"): - SeamMultiWorkspace.from_personal_access_token("seam_apikey_token") + SeamWithoutWorkspace.from_personal_access_token("seam_apikey_token") with pytest.raises(SeamInvalidTokenError, match=r"Client Session Token"): - SeamMultiWorkspace.from_personal_access_token("seam_cst") + SeamWithoutWorkspace.from_personal_access_token("seam_cst") with pytest.raises(SeamInvalidTokenError, match=r"JWT"): - SeamMultiWorkspace.from_personal_access_token("ey") + SeamWithoutWorkspace.from_personal_access_token("ey") with pytest.raises(SeamInvalidTokenError, match=r"Publishable Key"): - SeamMultiWorkspace.from_personal_access_token("seam_pk_token") + SeamWithoutWorkspace.from_personal_access_token("seam_pk_token")