codeoceansdk.Capsule
1import logging 2from dataclasses import asdict, dataclass, field as dc_field 3from enum import Enum 4from typing import Optional 5 6from codeoceansdk.CodeOcean import CodeOcean 7from codeoceansdk.Computation import Computation 8 9logger = logging.getLogger(__name__) 10 11 12@dataclass(frozen=True) 13class OriginalCapsuleInfo: 14 id: str = None 15 """Metadata id""" 16 major_version: int = None 17 """Major version number""" 18 minor_version: int = None 19 """Minor version number""" 20 name: str = None 21 """Name of original pipeline""" 22 created: int = None 23 """Creation time""" 24 public: bool = None 25 """Is original capsule public""" 26 27 28@dataclass(frozen=True) 29class SubmissionInfo: 30 timestamp: int = None 31 """Submission time""" 32 commit: str = None 33 """Submission commit hash""" 34 verification_capsule: str = None 35 """Verification capsule ID""" 36 verified: bool = None 37 """Indicates whether the capsule was verified""" 38 verified_timestamp: int = None 39 """Verification time""" 40 41 42@dataclass(frozen=True, slots=True) 43class Version: 44 """Capsule version""" 45 major_version: int 46 """Major version""" 47 minor_version: int 48 """Minor version""" 49 publish_time: int 50 """Publish timestamp""" 51 doi: str = None 52 """Digital identifier for capsule""" 53 54 55@dataclass(frozen=True, slots=True) 56class Article: 57 """If capsule is attached to a publication, what article is it attached to""" 58 url: str = None 59 """Article URL""" 60 id: str = None 61 """Article ID""" 62 doi: str = None 63 """Digital identifier for publication""" 64 citation: str = None 65 """Article citation""" 66 state: Enum("state", ["in_review", "published"]) = None 67 """Publication state (i.e., has it been published yet)""" 68 name: str = None 69 """Article name""" 70 journal_name: str = None 71 """Journal the article appears in""" 72 publish_time: int = None 73 """Publication timestamp""" 74 75 76@dataclass(frozen=True, slots=True) 77class UserPermission: 78 """Permissions for specific user""" 79 email: str 80 """Email address for user""" 81 role: Enum("role", ["owner, editor, viewer", "discoverable"]) 82 """Permission level to set for user""" 83 84 85@dataclass(frozen=True, slots=True) 86class GroupPermission: 87 """Permissions for group of users""" 88 group: str 89 """Group name""" 90 role: Enum("role", ["owner", "editor", "viewer", "discoverable"]) 91 """Permission level to set for group""" 92 93 94@dataclass(frozen=True, slots=True) 95class EveryonePermission: 96 """Permission for all users""" 97 role: Enum("role", ["viewer", "discoverable", "none"]) 98 """Permission level to set for everyone""" 99 100 101@dataclass(kw_only=True) 102class Capsule(CodeOcean): 103 id: str 104 """Capsule internal id""" 105 created: int = 0 106 """Capsule creation time""" 107 name: str = "" 108 """Capsule display name""" 109 status: Enum( 110 "status", ["non_published", "submitted", "publishing", "published", "verified"] 111 ) = "non_published" 112 """Whether or not capsule is published""" 113 owner: str = "" 114 """Capsule owner id""" 115 slug: str = "" 116 """Alternate capsule id""" 117 field: Optional[str] = None 118 """Capsule research field""" 119 description: Optional[str] = None 120 """Capsule description""" 121 cloned_from_url: Optional[str] = None 122 """If this is a capsule cloned from github, what url was it""" 123 keywords: Optional[list[str]] = dc_field(default_factory=list) 124 """Keywords describing capsule (optional)""" 125 article: Optional[Article] = None 126 """Capsule article info (optional)""" 127 versions: Optional[list[Version]] = dc_field(default_factory=list) 128 """Capsule versions (if published) (optional)""" 129 published_capsule: Optional[str] = None 130 """Published capsule id (separate from original)""" 131 original_capsule: Optional[OriginalCapsuleInfo] = None 132 """Original capsule info (if duplicated) (optional)""" 133 submission: Optional[SubmissionInfo] = None 134 """Submission info (if capsule submitted for publication) (optional)""" 135 136 def __post_init__(self): 137 super().__post_init__() 138 self.capsule_url = f"{self.api_url}/capsules/{self.id}" 139 140 def _parse_comp_response(self, computation_list: list): 141 """ 142 Parse response from list of dictionaries containing 143 computational parameters 144 145 :param computation_list: Input list of dictionary of computation parameters 146 :return: list of Computation objects 147 """ 148 computations = [] 149 for curr_dict in computation_list: 150 computations.append( 151 Computation.from_dict( 152 computation_dict=curr_dict, api_key=self.api_key, domain=self.domain 153 ) 154 ) 155 return computations 156 157 def get_capsule_runs(self): 158 """Get previous capsule runs 159 160 :return: List of Computation objects. 161 """ 162 input_url = f"{self.capsule_url}/computations" 163 logger.debug(f"Input url: {input_url}") 164 req = self.get(input_url) 165 computations = self._parse_comp_response(computation_list=req.json()) 166 167 logger.info("Returned runs: {}".format(len(computations))) 168 return computations 169 170 def get_capsule(self): 171 """ 172 Get capsule information 173 """ 174 req = self.get(self.capsule_url) 175 new_capsule = self.from_dict(req.json(), self.domain, self.api_key) 176 self.__dict__.update(new_capsule.__dict__) 177 178 @staticmethod 179 def from_dict(capsule_dict, domain, api_key): 180 """ 181 Parse dictionary to Capsule object 182 183 :param domain: Code Ocean domain 184 :param api_key: Capsule api. 185 :param capsule_dict: Input dictionary of capsule parameters. 186 :return: Computation object. 187 """ 188 if "article" in capsule_dict: 189 capsule_dict["article"] = Article(**capsule_dict["article"]) 190 if "versions" in capsule_dict: 191 capsule_dict["versions"] = [Version(**x) for x in capsule_dict["versions"]] 192 if "original_capsule" in capsule_dict: 193 capsule_dict["original_capsule"] = OriginalCapsuleInfo( 194 **capsule_dict["original_capsule"] 195 ) 196 if "submission" in capsule_dict: 197 capsule_dict["submission"] = SubmissionInfo(**capsule_dict["submission"]) 198 199 capsule_dict["domain"] = domain 200 capsule_dict["api_key"] = api_key 201 return Capsule(**capsule_dict) 202 203 def run_capsule_computation( 204 self, parameters: list = None, data_assets: list = None 205 ): 206 """ 207 Run a capsule. 208 209 :param parameters: List of parameters to pass to capsule. 210 Should be the same order as in the App Panel. 211 :param data_assets: List of dictionaries containing "id" and "mount" keys. 212 id is the data asset id, mount is the location to mount it in the capsule. 213 :return: Computation object. 214 """ 215 logger.info(f"Running capsule computation on {self.id}") 216 input_url = f"{self.api_url}/computations" 217 218 logger.debug(f"Input url: {input_url}") 219 logger.debug(f"Parameters {parameters}") 220 logger.debug(f"Data assets {data_assets}") 221 222 payload = {"capsule_id": self.id} 223 if parameters: 224 payload["parameters"] = parameters 225 if data_assets: 226 payload["data_assets"] = data_assets 227 req = self.post(input_url, payload) 228 return Computation.from_dict(req.json(), self.domain, self.api_key) 229 230 def set_capsule_permissions( 231 self, 232 users: list[UserPermission] = None, 233 groups: list[GroupPermission] = None, 234 everyone: EveryonePermission = None, 235 ): 236 """ 237 238 :param users: User permissions to set 239 :param groups: Group permissions to set 240 :param everyone: Permissions for everyone with access to the capsule 241 """ 242 input_url = f"{self.api_url}/capsules/{self.id}/permissions" 243 244 logger.debug(f"Input url: {input_url}") 245 logger.debug(f"Users {users}") 246 logger.debug(f"groups {groups}") 247 logger.debug(f"everyone {everyone}") 248 249 payload = {} 250 if users: 251 payload["users"] = [asdict(x) for x in users] 252 if groups: 253 payload["groups"] = [asdict(x) for x in groups] 254 if everyone: 255 payload["everyone"] = asdict(everyone)["role"] 256 257 self.post(input_url, payload)
logger =
<Logger codeoceansdk.Capsule (WARNING)>
@dataclass(frozen=True)
class
OriginalCapsuleInfo:
13@dataclass(frozen=True) 14class OriginalCapsuleInfo: 15 id: str = None 16 """Metadata id""" 17 major_version: int = None 18 """Major version number""" 19 minor_version: int = None 20 """Minor version number""" 21 name: str = None 22 """Name of original pipeline""" 23 created: int = None 24 """Creation time""" 25 public: bool = None 26 """Is original capsule public"""
@dataclass(frozen=True)
class
SubmissionInfo:
29@dataclass(frozen=True) 30class SubmissionInfo: 31 timestamp: int = None 32 """Submission time""" 33 commit: str = None 34 """Submission commit hash""" 35 verification_capsule: str = None 36 """Verification capsule ID""" 37 verified: bool = None 38 """Indicates whether the capsule was verified""" 39 verified_timestamp: int = None 40 """Verification time"""
@dataclass(frozen=True, slots=True)
class
Version:
43@dataclass(frozen=True, slots=True) 44class Version: 45 """Capsule version""" 46 major_version: int 47 """Major version""" 48 minor_version: int 49 """Minor version""" 50 publish_time: int 51 """Publish timestamp""" 52 doi: str = None 53 """Digital identifier for capsule"""
Capsule version
@dataclass(frozen=True, slots=True)
class
Article:
56@dataclass(frozen=True, slots=True) 57class Article: 58 """If capsule is attached to a publication, what article is it attached to""" 59 url: str = None 60 """Article URL""" 61 id: str = None 62 """Article ID""" 63 doi: str = None 64 """Digital identifier for publication""" 65 citation: str = None 66 """Article citation""" 67 state: Enum("state", ["in_review", "published"]) = None 68 """Publication state (i.e., has it been published yet)""" 69 name: str = None 70 """Article name""" 71 journal_name: str = None 72 """Journal the article appears in""" 73 publish_time: int = None 74 """Publication timestamp"""
If capsule is attached to a publication, what article is it attached to
@dataclass(frozen=True, slots=True)
class
UserPermission:
77@dataclass(frozen=True, slots=True) 78class UserPermission: 79 """Permissions for specific user""" 80 email: str 81 """Email address for user""" 82 role: Enum("role", ["owner, editor, viewer", "discoverable"]) 83 """Permission level to set for user"""
Permissions for specific user
@dataclass(frozen=True, slots=True)
class
GroupPermission:
86@dataclass(frozen=True, slots=True) 87class GroupPermission: 88 """Permissions for group of users""" 89 group: str 90 """Group name""" 91 role: Enum("role", ["owner", "editor", "viewer", "discoverable"]) 92 """Permission level to set for group"""
Permissions for group of users
@dataclass(frozen=True, slots=True)
class
EveryonePermission:
95@dataclass(frozen=True, slots=True) 96class EveryonePermission: 97 """Permission for all users""" 98 role: Enum("role", ["viewer", "discoverable", "none"]) 99 """Permission level to set for everyone"""
Permission for all users
102@dataclass(kw_only=True) 103class Capsule(CodeOcean): 104 id: str 105 """Capsule internal id""" 106 created: int = 0 107 """Capsule creation time""" 108 name: str = "" 109 """Capsule display name""" 110 status: Enum( 111 "status", ["non_published", "submitted", "publishing", "published", "verified"] 112 ) = "non_published" 113 """Whether or not capsule is published""" 114 owner: str = "" 115 """Capsule owner id""" 116 slug: str = "" 117 """Alternate capsule id""" 118 field: Optional[str] = None 119 """Capsule research field""" 120 description: Optional[str] = None 121 """Capsule description""" 122 cloned_from_url: Optional[str] = None 123 """If this is a capsule cloned from github, what url was it""" 124 keywords: Optional[list[str]] = dc_field(default_factory=list) 125 """Keywords describing capsule (optional)""" 126 article: Optional[Article] = None 127 """Capsule article info (optional)""" 128 versions: Optional[list[Version]] = dc_field(default_factory=list) 129 """Capsule versions (if published) (optional)""" 130 published_capsule: Optional[str] = None 131 """Published capsule id (separate from original)""" 132 original_capsule: Optional[OriginalCapsuleInfo] = None 133 """Original capsule info (if duplicated) (optional)""" 134 submission: Optional[SubmissionInfo] = None 135 """Submission info (if capsule submitted for publication) (optional)""" 136 137 def __post_init__(self): 138 super().__post_init__() 139 self.capsule_url = f"{self.api_url}/capsules/{self.id}" 140 141 def _parse_comp_response(self, computation_list: list): 142 """ 143 Parse response from list of dictionaries containing 144 computational parameters 145 146 :param computation_list: Input list of dictionary of computation parameters 147 :return: list of Computation objects 148 """ 149 computations = [] 150 for curr_dict in computation_list: 151 computations.append( 152 Computation.from_dict( 153 computation_dict=curr_dict, api_key=self.api_key, domain=self.domain 154 ) 155 ) 156 return computations 157 158 def get_capsule_runs(self): 159 """Get previous capsule runs 160 161 :return: List of Computation objects. 162 """ 163 input_url = f"{self.capsule_url}/computations" 164 logger.debug(f"Input url: {input_url}") 165 req = self.get(input_url) 166 computations = self._parse_comp_response(computation_list=req.json()) 167 168 logger.info("Returned runs: {}".format(len(computations))) 169 return computations 170 171 def get_capsule(self): 172 """ 173 Get capsule information 174 """ 175 req = self.get(self.capsule_url) 176 new_capsule = self.from_dict(req.json(), self.domain, self.api_key) 177 self.__dict__.update(new_capsule.__dict__) 178 179 @staticmethod 180 def from_dict(capsule_dict, domain, api_key): 181 """ 182 Parse dictionary to Capsule object 183 184 :param domain: Code Ocean domain 185 :param api_key: Capsule api. 186 :param capsule_dict: Input dictionary of capsule parameters. 187 :return: Computation object. 188 """ 189 if "article" in capsule_dict: 190 capsule_dict["article"] = Article(**capsule_dict["article"]) 191 if "versions" in capsule_dict: 192 capsule_dict["versions"] = [Version(**x) for x in capsule_dict["versions"]] 193 if "original_capsule" in capsule_dict: 194 capsule_dict["original_capsule"] = OriginalCapsuleInfo( 195 **capsule_dict["original_capsule"] 196 ) 197 if "submission" in capsule_dict: 198 capsule_dict["submission"] = SubmissionInfo(**capsule_dict["submission"]) 199 200 capsule_dict["domain"] = domain 201 capsule_dict["api_key"] = api_key 202 return Capsule(**capsule_dict) 203 204 def run_capsule_computation( 205 self, parameters: list = None, data_assets: list = None 206 ): 207 """ 208 Run a capsule. 209 210 :param parameters: List of parameters to pass to capsule. 211 Should be the same order as in the App Panel. 212 :param data_assets: List of dictionaries containing "id" and "mount" keys. 213 id is the data asset id, mount is the location to mount it in the capsule. 214 :return: Computation object. 215 """ 216 logger.info(f"Running capsule computation on {self.id}") 217 input_url = f"{self.api_url}/computations" 218 219 logger.debug(f"Input url: {input_url}") 220 logger.debug(f"Parameters {parameters}") 221 logger.debug(f"Data assets {data_assets}") 222 223 payload = {"capsule_id": self.id} 224 if parameters: 225 payload["parameters"] = parameters 226 if data_assets: 227 payload["data_assets"] = data_assets 228 req = self.post(input_url, payload) 229 return Computation.from_dict(req.json(), self.domain, self.api_key) 230 231 def set_capsule_permissions( 232 self, 233 users: list[UserPermission] = None, 234 groups: list[GroupPermission] = None, 235 everyone: EveryonePermission = None, 236 ): 237 """ 238 239 :param users: User permissions to set 240 :param groups: Group permissions to set 241 :param everyone: Permissions for everyone with access to the capsule 242 """ 243 input_url = f"{self.api_url}/capsules/{self.id}/permissions" 244 245 logger.debug(f"Input url: {input_url}") 246 logger.debug(f"Users {users}") 247 logger.debug(f"groups {groups}") 248 logger.debug(f"everyone {everyone}") 249 250 payload = {} 251 if users: 252 payload["users"] = [asdict(x) for x in users] 253 if groups: 254 payload["groups"] = [asdict(x) for x in groups] 255 if everyone: 256 payload["everyone"] = asdict(everyone)["role"] 257 258 self.post(input_url, payload)
Capsule( *, domain: str, api_key: str, id: str, created: int = 0, name: str = '', status: codeoceansdk.Capsule.status = 'non_published', owner: str = '', slug: str = '', field: Optional[str] = None, description: Optional[str] = None, cloned_from_url: Optional[str] = None, keywords: Optional[list[str]] = <factory>, article: Optional[Article] = None, versions: Optional[list[Version]] = <factory>, published_capsule: Optional[str] = None, original_capsule: Optional[OriginalCapsuleInfo] = None, submission: Optional[SubmissionInfo] = None)
def
get_capsule_runs(self):
158 def get_capsule_runs(self): 159 """Get previous capsule runs 160 161 :return: List of Computation objects. 162 """ 163 input_url = f"{self.capsule_url}/computations" 164 logger.debug(f"Input url: {input_url}") 165 req = self.get(input_url) 166 computations = self._parse_comp_response(computation_list=req.json()) 167 168 logger.info("Returned runs: {}".format(len(computations))) 169 return computations
Get previous capsule runs
Returns
List of Computation objects.
def
get_capsule(self):
171 def get_capsule(self): 172 """ 173 Get capsule information 174 """ 175 req = self.get(self.capsule_url) 176 new_capsule = self.from_dict(req.json(), self.domain, self.api_key) 177 self.__dict__.update(new_capsule.__dict__)
Get capsule information
@staticmethod
def
from_dict(capsule_dict, domain, api_key):
179 @staticmethod 180 def from_dict(capsule_dict, domain, api_key): 181 """ 182 Parse dictionary to Capsule object 183 184 :param domain: Code Ocean domain 185 :param api_key: Capsule api. 186 :param capsule_dict: Input dictionary of capsule parameters. 187 :return: Computation object. 188 """ 189 if "article" in capsule_dict: 190 capsule_dict["article"] = Article(**capsule_dict["article"]) 191 if "versions" in capsule_dict: 192 capsule_dict["versions"] = [Version(**x) for x in capsule_dict["versions"]] 193 if "original_capsule" in capsule_dict: 194 capsule_dict["original_capsule"] = OriginalCapsuleInfo( 195 **capsule_dict["original_capsule"] 196 ) 197 if "submission" in capsule_dict: 198 capsule_dict["submission"] = SubmissionInfo(**capsule_dict["submission"]) 199 200 capsule_dict["domain"] = domain 201 capsule_dict["api_key"] = api_key 202 return Capsule(**capsule_dict)
Parse dictionary to Capsule object
Parameters
- domain: Code Ocean domain
- api_key: Capsule api.
- capsule_dict: Input dictionary of capsule parameters.
Returns
Computation object.
def
run_capsule_computation(self, parameters: list = None, data_assets: list = None):
204 def run_capsule_computation( 205 self, parameters: list = None, data_assets: list = None 206 ): 207 """ 208 Run a capsule. 209 210 :param parameters: List of parameters to pass to capsule. 211 Should be the same order as in the App Panel. 212 :param data_assets: List of dictionaries containing "id" and "mount" keys. 213 id is the data asset id, mount is the location to mount it in the capsule. 214 :return: Computation object. 215 """ 216 logger.info(f"Running capsule computation on {self.id}") 217 input_url = f"{self.api_url}/computations" 218 219 logger.debug(f"Input url: {input_url}") 220 logger.debug(f"Parameters {parameters}") 221 logger.debug(f"Data assets {data_assets}") 222 223 payload = {"capsule_id": self.id} 224 if parameters: 225 payload["parameters"] = parameters 226 if data_assets: 227 payload["data_assets"] = data_assets 228 req = self.post(input_url, payload) 229 return Computation.from_dict(req.json(), self.domain, self.api_key)
Run a capsule.
Parameters
- parameters: List of parameters to pass to capsule. Should be the same order as in the App Panel.
- data_assets: List of dictionaries containing "id" and "mount" keys. id is the data asset id, mount is the location to mount it in the capsule.
Returns
Computation object.
def
set_capsule_permissions( self, users: list[UserPermission] = None, groups: list[GroupPermission] = None, everyone: EveryonePermission = None):
231 def set_capsule_permissions( 232 self, 233 users: list[UserPermission] = None, 234 groups: list[GroupPermission] = None, 235 everyone: EveryonePermission = None, 236 ): 237 """ 238 239 :param users: User permissions to set 240 :param groups: Group permissions to set 241 :param everyone: Permissions for everyone with access to the capsule 242 """ 243 input_url = f"{self.api_url}/capsules/{self.id}/permissions" 244 245 logger.debug(f"Input url: {input_url}") 246 logger.debug(f"Users {users}") 247 logger.debug(f"groups {groups}") 248 logger.debug(f"everyone {everyone}") 249 250 payload = {} 251 if users: 252 payload["users"] = [asdict(x) for x in users] 253 if groups: 254 payload["groups"] = [asdict(x) for x in groups] 255 if everyone: 256 payload["everyone"] = asdict(everyone)["role"] 257 258 self.post(input_url, payload)
Parameters
- users: User permissions to set
- groups: Group permissions to set
- everyone: Permissions for everyone with access to the capsule