11from __future__ import annotations
22
3+ from typing import Any , Iterator , Optional
4+ import builtins
5+
36from ..types import ExecutionMode , Workspace
47from ._base import _Service
58
69
7- def _ws_from (d , org : str | None = None ) -> Workspace :
8- attr = d .get ("attributes" , {})
10+ def _safe_str (v : Any , default : str = "" ) -> str :
11+ return v if isinstance (v , str ) else (str (v ) if v is not None else default )
12+
13+
14+ def _em_safe (v : Any ) -> ExecutionMode | None :
15+ # Only accept strings; map to enum if known, else None
16+ if not isinstance (v , str ):
17+ return None
18+ return ExecutionMode ._value2member_map_ .get (v ) # type: ignore[return-value]
19+
20+
21+ def _ws_from (d : dict [str , Any ], org : str | None = None ) -> Workspace :
22+ attr : dict [str , Any ] = d .get ("attributes" , {}) or {}
23+
24+ # Coerce to required string fields (empty string fallback keeps mypy happy)
25+ id_str : str = _safe_str (d .get ("id" ))
26+ name_str : str = _safe_str (attr .get ("name" ))
27+ org_str : str = _safe_str (org if org is not None else attr .get ("organization" ))
28+
29+ # Optional fields
30+ em : ExecutionMode | None = _em_safe (attr .get ("execution-mode" ))
31+
32+ proj_id : Optional [str ] = None
33+ proj = attr .get ("project" )
34+ if isinstance (proj , dict ):
35+ proj_id = proj .get ("id" ) if isinstance (proj .get ("id" ), str ) else None
36+
37+ tags_val = attr .get ("tags" , []) or []
38+ tags_list : list [str ] = list (tags_val ) if isinstance (tags_val , (list , tuple )) else []
39+
940 return Workspace (
10- id = d .get ("id" ),
11- name = attr .get ("name" ),
12- organization = org or attr .get ("organization" ),
13- execution_mode = ExecutionMode (attr .get ("execution-mode" ))
14- if attr .get ("execution-mode" )
15- else None ,
16- project_id = attr .get ("project" , {}).get ("id" )
17- if isinstance (attr .get ("project" ), dict )
18- else None ,
19- tags = attr .get ("tags" , []) or [],
41+ id = id_str ,
42+ name = name_str ,
43+ organization = org_str ,
44+ execution_mode = em ,
45+ project_id = proj_id ,
46+ tags = tags_list ,
2047 )
2148
2249
2350class Workspaces (_Service ):
24- def list (self , organization : str , * , search : str | None = None ):
25- params = {}
51+ def list (self , organization : str , * , search : str | None = None ) -> Iterator [ Workspace ] :
52+ params : dict [ str , Any ] = {}
2653 if search :
2754 params ["search[name]" ] = search
2855 path = f"/api/v2/organizations/{ organization } /workspaces"
@@ -45,26 +72,34 @@ def create(
4572 * ,
4673 execution_mode : str | None = "remote" ,
4774 project_id : str | None = None ,
48- tags : list [str ] | None = None ,
75+ tags : builtins . list [str ] | None = None ,
4976 ) -> Workspace :
50- body = {"data" : {"type" : "workspaces" , "attributes" : {"name" : name }}}
77+ body : dict [str , Any ] = {
78+ "data" : {"type" : "workspaces" , "attributes" : {"name" : name }}
79+ }
5180 if execution_mode :
5281 body ["data" ]["attributes" ]["execution-mode" ] = execution_mode
5382 if project_id :
54- body ["data" ]["relationships" ] = {
55- "project" : {"data" : {"type" : "projects" , "id" : project_id }}
83+ body ["data" ].setdefault ("relationships" , {})
84+ body ["data" ]["relationships" ]["project" ] = {
85+ "data" : {"type" : "projects" , "id" : project_id }
5686 }
5787 if tags :
58- body ["data" ]["attributes" ]["tags" ] = tags
88+ body ["data" ]["attributes" ]["tags" ] = list (tags )
89+
5990 r = self .t .request (
6091 "POST" , f"/api/v2/organizations/{ organization } /workspaces" , json_body = body
6192 )
6293 return _ws_from (r .json ()["data" ], organization )
6394
64- def update (self , id : str , ** attrs ) -> Workspace :
65- body = {"data" : {"type" : "workspaces" , "id" : id , "attributes" : {}}}
95+ def update (self , id : str , ** attrs : Any ) -> Workspace :
96+ body : dict [ str , Any ] = {"data" : {"type" : "workspaces" , "id" : id , "attributes" : {}}}
6697 for k , v in attrs .items ():
67- body ["data" ]["attributes" ][k .replace ("_" , "-" )] = v
98+ kk = k .replace ("_" , "-" )
99+ # Map enum back to string if provided
100+ if kk == "execution-mode" and isinstance (v , ExecutionMode ):
101+ v = v .value
102+ body ["data" ]["attributes" ][kk ] = v
68103 r = self .t .request ("PATCH" , f"/api/v2/workspaces/{ id } " , json_body = body )
69104 return _ws_from (r .json ()["data" ], None )
70105
0 commit comments