@@ -26,6 +26,29 @@ class CapsuleSortBy(StrEnum):
2626 Name = "name"
2727
2828
29+ class AppPanelDataAssetKind (StrEnum ):
30+ """The kind of data asset displayed in an app panel.
31+
32+ - 'Internal' → Data stored inside Code Ocean.
33+ - 'External' → Data stored external to Code Ocean.
34+ - 'Combined' → Data containing multiple external data assets.
35+
36+ In pipelines, a data asset can only be replaced with one of the same kind.
37+ """
38+
39+ Internal = "internal"
40+ External = "external"
41+ Combined = "combined"
42+
43+
44+ class AppPanelParameterType (StrEnum ):
45+ """The type of parameter displayed in an app panel."""
46+
47+ Text = "text"
48+ List = "list"
49+ File = "file"
50+
51+
2952@dataclass_json
3053@dataclass (frozen = True )
3154class OriginalCapsuleInfo :
@@ -81,6 +104,10 @@ class Capsule:
81104 slug : str = dataclass_field (
82105 metadata = {"description" : "Alternate capsule ID (URL-friendly identifier)" },
83106 )
107+ last_accessed : Optional [int ] = dataclass_field (
108+ default = None ,
109+ metadata = {"description" : "Capsule last accessed time (int64 timestamp)" },
110+ )
84111 article : Optional [dict ] = dataclass_field (
85112 default = None ,
86113 metadata = {
@@ -245,6 +272,199 @@ class CapsuleSearchResults:
245272 )
246273
247274
275+ @dataclass_json
276+ @dataclass (frozen = True )
277+ class AppPanelCategories :
278+ """Categories for a capsule's App Panel parameters."""
279+
280+ id : str = dataclass_field (
281+ metadata = {"description" : "Unique identifier for the category." },
282+ )
283+ name : str = dataclass_field (
284+ metadata = {"description" : "Human-readable name of the category." },
285+ )
286+ description : Optional [str ] = dataclass_field (
287+ default = None ,
288+ metadata = {"description" : "Optional detailed description of the category." },
289+ )
290+ help_text : Optional [str ] = dataclass_field (
291+ default = None ,
292+ metadata = {"description" : "Optional help text providing guidance or additional information about the category." },
293+ )
294+
295+
296+ @dataclass_json
297+ @dataclass (frozen = True )
298+ class AppPanelParameters :
299+ """Parameters for a capsule's App Panel."""
300+
301+ name : str = dataclass_field (
302+ metadata = {"description" : "Parameter label/display name." }
303+ )
304+ type : AppPanelParameterType = dataclass_field (
305+ metadata = {"description" : "Type of the parameter (text, list, file)." }
306+ )
307+ category : Optional [str ] = dataclass_field (
308+ default = None ,
309+ metadata = {"description" : "ID of category the parameter belongs to." }
310+ )
311+ param_name : Optional [str ] = dataclass_field (
312+ default = None ,
313+ metadata = {"description" : "The parameter name/argument key" }
314+ )
315+ description : Optional [str ] = dataclass_field (
316+ default = None ,
317+ metadata = {"description" : "Description of the parameter." }
318+ )
319+ help_text : Optional [str ] = dataclass_field (
320+ default = None ,
321+ metadata = {"description" : "Help text for the parameter." }
322+ )
323+ value_type : Optional [str ] = dataclass_field (
324+ default = None ,
325+ metadata = {"description" : "Value type of the parameter." }
326+ )
327+ default_value : Optional [str ] = dataclass_field (
328+ default = None ,
329+ metadata = {"description" : "Default value of the parameter." }
330+ )
331+ required : Optional [bool ] = dataclass_field (
332+ default = None ,
333+ metadata = {"description" : "Indicates if the parameter is required." }
334+ )
335+ hidden : Optional [bool ] = dataclass_field (
336+ default = None ,
337+ metadata = {"description" : "Indicates if the parameter is hidden." }
338+ )
339+ minimum : Optional [float ] = dataclass_field (
340+ default = None ,
341+ metadata = {"description" : "Minimum value for the parameter." }
342+ )
343+ maximum : Optional [float ] = dataclass_field (
344+ default = None ,
345+ metadata = {"description" : "Maximum value for the parameter." }
346+ )
347+ pattern : Optional [str ] = dataclass_field (
348+ default = None ,
349+ metadata = {"description" : "Regular expression pattern for the parameter." }
350+ )
351+ value_options : Optional [list [str ]] = dataclass_field (
352+ default = None ,
353+ metadata = {"description" : "Allowed values for the parameter." }
354+ )
355+
356+
357+ @dataclass_json
358+ @dataclass (frozen = True )
359+ class AppPanelGeneral :
360+ """General information about a capsule's App Panel."""
361+
362+ title : Optional [str ] = dataclass_field (
363+ default = None ,
364+ metadata = {"description" : "Title of the App Panel." }
365+ )
366+ instructions : Optional [str ] = dataclass_field (
367+ default = None ,
368+ metadata = {"description" : "Instructions for using the App Panel." }
369+ )
370+ help_text : Optional [str ] = dataclass_field (
371+ default = None ,
372+ metadata = {"description" : "Help text for the App Panel." }
373+ )
374+
375+
376+ @dataclass_json
377+ @dataclass (frozen = True )
378+ class AppPanelDataAsset :
379+ """Data asset parameter for the App Panel."""
380+
381+ id : str = dataclass_field (
382+ metadata = {"description" : "Unique identifier for the data asset." }
383+ )
384+ mount : str = dataclass_field (
385+ metadata = {"description" : "Mount path of the data asset within the capsule. "
386+ "Use this mount path to replace the currently attached data asset with your own" }
387+ )
388+ name : str = dataclass_field (
389+ metadata = {"description" : "Display name of the data asset." }
390+ )
391+ kind : AppPanelDataAssetKind = dataclass_field (
392+ metadata = {"description" : "Kind of the data asset (internal, external, combined)." }
393+ )
394+ accessible : bool = dataclass_field (
395+ metadata = {"description" : "Indicates if the data asset is accessible to the user." }
396+ )
397+ description : Optional [str ] = dataclass_field (
398+ default = None ,
399+ metadata = {"description" : "Optional description of the data asset parameter." }
400+ )
401+ help_text : Optional [str ] = dataclass_field (
402+ default = None ,
403+ metadata = {"description" : "Optional help text for the data asset parameter." }
404+ )
405+
406+
407+ @dataclass_json
408+ @dataclass (frozen = True )
409+ class AppPanelResult :
410+ """Selected result files to display once the computation is complete."""
411+
412+ file_name : str = dataclass_field (
413+ metadata = {"description" : "Name of the result file." }
414+ )
415+
416+
417+ @dataclass_json
418+ @dataclass (frozen = True )
419+ class AppPanelProcess :
420+ """Pipeline process name and its corresponding app panel (for pipelines of capsules only)"""
421+
422+ name : str = dataclass_field (
423+ metadata = {"description" : "Name of the pipeline process." }
424+ )
425+ categories : Optional [AppPanelCategories ] = dataclass_field (
426+ default = None ,
427+ metadata = {"description" : "Categories for the pipeline process's app panel parameters." }
428+ )
429+ parameters : Optional [AppPanelParameters ] = dataclass_field (
430+ default = None ,
431+ metadata = {"description" : "Parameters for the pipeline process's app panel." }
432+ )
433+
434+
435+ @dataclass_json
436+ @dataclass (frozen = True )
437+ class AppPanel :
438+ """App Panel configuration for a capsule or pipeline, including general info, data assets,
439+ categories, parameters, and results.
440+ """
441+
442+ general : Optional [AppPanelGeneral ] = dataclass_field (
443+ default = None ,
444+ metadata = {"description" : "General information about the App Panel." }
445+ )
446+ data_assets : Optional [list [AppPanelDataAsset ]] = dataclass_field (
447+ default = None ,
448+ metadata = {"description" : "List of data assets used in the App Panel." }
449+ )
450+ categories : Optional [list [AppPanelCategories ]] = dataclass_field (
451+ default = None ,
452+ metadata = {"description" : "Categories for organizing App Panel parameters." }
453+ )
454+ parameters : Optional [list [AppPanelParameters ]] = dataclass_field (
455+ default = None ,
456+ metadata = {"description" : "Parameters for the App Panel." }
457+ )
458+ results : Optional [list [AppPanelResult ]] = dataclass_field (
459+ default = None ,
460+ metadata = {"description" : "Result files to display after computation." }
461+ )
462+ processes : Optional [list [AppPanelProcess ]] = dataclass_field (
463+ default = None ,
464+ metadata = {"description" : "Pipeline processes and their App Panels." }
465+ )
466+
467+
248468@dataclass
249469class Capsules :
250470 """Client for interacting with Code Ocean capsule APIs."""
@@ -257,6 +477,16 @@ def get_capsule(self, capsule_id: str) -> Capsule:
257477
258478 return Capsule .from_dict (res .json ())
259479
480+ def delete_capsule (self , capsule_id : str ):
481+ """Delete a capsule permanently."""
482+ self .client .delete (f"capsules/{ capsule_id } " )
483+
484+ def get_capsule_app_panel (self , capsule_id : str , version : Optional [int ] = None ) -> AppPanel :
485+ """Retrieve app panel information for a specific capsule by its ID."""
486+ res = self .client .get (f"capsules/{ capsule_id } /app_panel" , params = {"version" : version } if version else None )
487+
488+ return AppPanel .from_dict (res .json ())
489+
260490 def list_computations (self , capsule_id : str ) -> list [Computation ]:
261491 """Get all computations associated with a specific capsule."""
262492 res = self .client .get (f"capsules/{ capsule_id } /computations" )
@@ -290,6 +520,13 @@ def detach_data_assets(self, capsule_id: str, data_assets: list[str]):
290520 json = data_assets ,
291521 )
292522
523+ def archive_capsule (self , capsule_id : str , archive : bool ):
524+ """Archive or unarchive a capsule to control its visibility and accessibility."""
525+ self .client .patch (
526+ f"capsules/{ capsule_id } /archive" ,
527+ params = {"archive" : archive },
528+ )
529+
293530 def search_capsules (self , search_params : CapsuleSearchParams ) -> CapsuleSearchResults :
294531 """Search for capsules with filtering, sorting, and pagination
295532 options."""
0 commit comments