Skip to content

Commit 4376dbf

Browse files
authored
Rename mentions of plugins to capsules in the API (#6)
This brings the Python API up to speed with the naming we're using in the BrainFrame documentation. The server itself still calls them plugins in API endpoints and errors, so some mention of "plugins" still exists.
1 parent 0fbec00 commit 4376dbf

9 files changed

Lines changed: 192 additions & 193 deletions

File tree

brainframe/api/bf_codecs/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
from .identity_codecs import Identity, Encoding
1111
from .detection_codecs import Attribute, Detection
1212
from .zone_codecs import Zone, ZoneStatus
13-
from .plugin_codecs import (
14-
PluginOption,
15-
Plugin,
13+
from .capsule_codecs import (
14+
CapsuleOption,
15+
Capsule,
1616
NodeDescription,
1717
)
1818
from .premises_codecs import Premises

brainframe/api/bf_codecs/plugin_codecs.py renamed to brainframe/api/bf_codecs/capsule_codecs.py

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77

88

99
@dataclass
10-
class PluginOption(Codec):
11-
"""A single configuration option for a plugin. Defines what type of option
10+
class CapsuleOption(Codec):
11+
"""A single configuration option for a capsule. Defines what type of option
1212
it is and its potential values.
1313
14-
There are two kinds of plugin options. Stream plugin options apply only to
15-
the stream they are attached to. Global plugin options apply to all
16-
streams, but are overridden by stream plugin options.
14+
There are two kinds of capsule options. Stream capsule options apply only
15+
to the stream they are attached to. Global capsule options apply to all
16+
streams, but are overridden by stream capsule options.
1717
"""
1818

1919
class Type(Enum):
20-
"""The data type of a plugin option"""
20+
"""The data type of a capsule option"""
2121

2222
FLOAT = "float"
2323
INT = "int"
@@ -57,7 +57,7 @@ def values(cls):
5757
"""
5858

5959
description: str
60-
"""A human-readable description of the plugin's capabilities"""
60+
"""A human-readable description of the capsule's capabilities"""
6161

6262
def to_dict(self):
6363
d = dict(self.__dict__)
@@ -66,42 +66,42 @@ def to_dict(self):
6666

6767
@staticmethod
6868
def from_dict(d):
69-
type_ = PluginOption.Type(d["type"])
70-
return PluginOption(type=type_,
71-
default=d["default"],
72-
constraints=d["constraints"],
73-
description=d["description"])
69+
type_ = CapsuleOption.Type(d["type"])
70+
return CapsuleOption(type=type_,
71+
default=d["default"],
72+
constraints=d["constraints"],
73+
description=d["description"])
7474

7575

7676
@dataclass
7777
class NodeDescription(Codec):
78-
"""A description of a DetectionNode, used by plugins to define what kinds
79-
of inputs and outputs a plugin uses.
78+
"""A description of a DetectionNode, used by capsules to define what kinds
79+
of inputs and outputs a capsule uses.
8080
"""
8181

8282
class Size(Enum):
83-
"""Describes the amount of DetectionNodes a plugin takes as input or
83+
"""Describes the amount of DetectionNodes a capsule takes as input or
8484
provides as output.
8585
"""
8686

8787
NONE = "none"
88-
"""Input: The plugin takes nothing as input, like for an object
88+
"""Input: The capsule takes nothing as input, like for an object
8989
detector.
9090
91-
Output: Plugins cannot have a NONE output.
91+
Output: Capsules cannot have a NONE output.
9292
"""
9393
SINGLE = "single"
94-
"""Input: The plugin takes a single DetectionNode as input, like for a
94+
"""Input: The capsule takes a single DetectionNode as input, like for a
9595
classifier.
9696
97-
Output: The plugin provides a single modified DetectionNode as output,
97+
Output: The capsule provides a single modified DetectionNode as output,
9898
like for a classifier.
9999
"""
100100
ALL = "all"
101-
"""Input: The plugin takes all instances of a class as input, like for
101+
"""Input: The capsule takes all instances of a class as input, like for
102102
a tracker.
103103
104-
Output: The plugin provides all instances of a class as output, like
104+
Output: The capsule provides all instances of a class as output, like
105105
for a detector.
106106
"""
107107

@@ -159,34 +159,34 @@ def from_dict(d):
159159

160160

161161
@dataclass
162-
class Plugin(Codec):
163-
"""Metadata on a loaded plugin."""
162+
class Capsule(Codec):
163+
"""Metadata on a loaded capsule."""
164164

165165
name: str
166-
"""The name of the plugin"""
166+
"""The name of the capsule"""
167167

168168
version: int
169-
"""The plugin's version"""
169+
"""The capsule's version"""
170170

171171
description: str
172-
"""A human-readable description of what the plugin does"""
172+
"""A human-readable description of what the capsule does"""
173173

174174
input_type: NodeDescription
175-
"""Describes the type of inference data that this plugin takes as input
175+
"""Describes the type of inference data that this capsule takes as input
176176
"""
177177

178178
output_type: NodeDescription
179-
"""Describes the type of inference data that this plugin produces"""
179+
"""Describes the type of inference data that this capsule produces"""
180180

181181
capability: NodeDescription
182-
"""A NodeDescription which describes what this plugin does to its
182+
"""A NodeDescription which describes what this capsule does to its
183183
input. It is the difference between the input and output
184-
NodeDescriptions. This field is useful for inspecting a plugin to find
184+
NodeDescriptions. This field is useful for inspecting a capsule to find
185185
what it can do.
186186
"""
187187

188-
options: Dict[str, PluginOption]
189-
"""A dict describing the configurable options of this plugin"""
188+
options: Dict[str, CapsuleOption]
189+
"""A dict describing the configurable options of this capsule"""
190190

191191
def to_dict(self):
192192
return {
@@ -202,13 +202,13 @@ def to_dict(self):
202202

203203
@staticmethod
204204
def from_dict(d):
205-
return Plugin(
205+
return Capsule(
206206
name=d["name"],
207207
version=d["version"],
208208
description=d["description"],
209209
input_type=NodeDescription.from_dict(d["input_type"]),
210210
output_type=NodeDescription.from_dict(d["output_type"]),
211211
capability=NodeDescription.from_dict(d["capability"]),
212-
options={key: PluginOption.from_dict(val)
212+
options={key: CapsuleOption.from_dict(val)
213213
for key, val in d["options"].items()},
214214
)

brainframe/api/bf_errors.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,16 +192,16 @@ class FrameNotFoundForAlertError(BaseAPIError):
192192
"""There was an attempt to get a frame for an alert that has no frame."""
193193

194194

195-
@_register_error()
196-
class PluginNotFoundError(BaseAPIError):
197-
"""There was an attempt to reference a plugin that does not exist."""
195+
@_register_error("PluginNotFoundError")
196+
class CapsuleNotFoundError(BaseAPIError):
197+
"""There was an attempt to reference a capsule that does not exist."""
198198

199199

200-
@_register_error()
201-
class InvalidPluginOptionError(BaseAPIError):
202-
"""The provided plugin options do not work for the given plugin. This could
203-
be because the option does not exist or the value for that option doesn't
204-
fit the constraints.
200+
@_register_error("InvalidPluginOptionError")
201+
class InvalidCapsuleOptionError(BaseAPIError):
202+
"""The provided capsule options do not work for the given capsule. This
203+
could be because the option does not exist or the value for that option
204+
doesn't fit the constraints.
205205
"""
206206

207207

brainframe/api/stub.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
class BrainFrameAPI(stubs.AlertStubMixin,
1212
stubs.AnalysisStubMixin,
1313
stubs.IdentityStubMixin,
14-
stubs.PluginStubMixin,
14+
stubs.CapsuleStubMixin,
1515
stubs.StreamStubMixin,
1616
stubs.ZoneStatusStubMixin,
1717
stubs.ZoneStubMixin,

brainframe/api/stubs/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from .alerts import AlertStubMixin
22
from .analysis import AnalysisStubMixin
33
from .identities import IdentityStubMixin
4-
from .plugins import PluginStubMixin
4+
from .capsules import CapsuleStubMixin
55
from .streams import StreamStubMixin
66
from .zone_statuses import ZoneStatusStubMixin
77
from .zones import ZoneStubMixin

brainframe/api/stubs/capsules.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import json
2+
from typing import Dict, List, Optional
3+
4+
from brainframe.api.bf_codecs import Capsule
5+
from .base_stub import BaseStub, DEFAULT_TIMEOUT
6+
7+
8+
class CapsuleStubMixin(BaseStub):
9+
"""Provides stubs to call APIs to inspect and configure capsules."""
10+
11+
def get_capsule(self, name,
12+
timeout=DEFAULT_TIMEOUT) -> Capsule:
13+
"""
14+
:param name: The name of the capsule to get
15+
:param timeout: The timeout to use for this request
16+
:return: Capsule with the given name
17+
"""
18+
req = f"/api/plugins/{name}"
19+
capsule, _ = self._get_json(req, timeout)
20+
return Capsule.from_dict(capsule)
21+
22+
def get_capsules(self, timeout=DEFAULT_TIMEOUT) -> List[Capsule]:
23+
"""
24+
:param timeout: The timeout to use for this request
25+
:return: All available capsules
26+
"""
27+
req = "/api/plugins"
28+
capsules, _ = self._get_json(req, timeout)
29+
return [Capsule.from_dict(d) for d in capsules]
30+
31+
def get_capsule_option_vals(self, capsule_name, stream_id=None,
32+
timeout=DEFAULT_TIMEOUT) \
33+
-> Dict[str, object]:
34+
"""Gets the current values for every capsule option. See the
35+
documentation for the CapsuleOption codec for more info about global
36+
and stream level options and how they interact.
37+
38+
:param capsule_name: The capsule to find options for
39+
:param stream_id: The ID of the stream. If this value is None, then the
40+
global options are returned for that capsule
41+
:param timeout: The timeout to use for this request
42+
:return: A dict where the key is the option name and the value is the
43+
option's current value
44+
"""
45+
if stream_id is None:
46+
req = f"/api/plugins/{capsule_name}/options"
47+
else:
48+
req = f"/api/streams/{stream_id}/plugins/{capsule_name}/options"
49+
capsule_option_vals, _ = self._get_json(req, timeout)
50+
51+
return capsule_option_vals
52+
53+
def set_capsule_option_vals(self, *, capsule_name, stream_id=None,
54+
option_vals: Dict[str, object],
55+
timeout=DEFAULT_TIMEOUT):
56+
"""Sets option values for a capsule.
57+
58+
:param capsule_name: The name of the capsule whose options to set
59+
:param stream_id: The ID of the stream, if these are stream-level
60+
options. If this value is None, then the global options are set
61+
:param option_vals: A dict where the key is the name of the option to
62+
set, and the value is the value to set that option to
63+
:param timeout: The timeout to use for this request
64+
"""
65+
if stream_id is None:
66+
req = f"/api/plugins/{capsule_name}/options"
67+
else:
68+
req = f"/api/streams/{stream_id}/plugins/{capsule_name}/options"
69+
70+
option_values_json = json.dumps(option_vals)
71+
self._put_json(req, timeout, option_values_json)
72+
73+
def patch_capsule_option_vals(self, *, capsule_name, stream_id=None,
74+
option_vals: Dict[str, object],
75+
timeout=DEFAULT_TIMEOUT):
76+
"""Patches option values for a capsule. Only the provided options are
77+
changed. To unset an option, provide that option with a value of None.
78+
79+
:param capsule_name: The name of the capsule whose options to set
80+
:param stream_id: The ID of the stream, if these are stream-level
81+
options. If this value is None, then the global options are set
82+
:param option_vals: A dict where the key is the name of the option to
83+
set, and the value is the value to set that option to
84+
:param timeout: The timeout to use for this request
85+
"""
86+
if stream_id is None:
87+
req = f"/api/plugins/{capsule_name}/options"
88+
else:
89+
req = f"/api/streams/{stream_id}/plugins/{capsule_name}/options"
90+
91+
option_values_json = json.dumps(option_vals)
92+
self._patch_json(req, timeout, option_values_json)
93+
94+
def is_capsule_active(self, capsule_name, stream_id=None,
95+
timeout=DEFAULT_TIMEOUT) -> bool:
96+
"""Returns True if the capsule is active. If a capsule is not marked as
97+
active, it will not run. Like capsule options, this can be configured
98+
globally and on a per-stream level.
99+
100+
:param capsule_name: The name of the capsule to get activity for
101+
:param stream_id: The ID of the stream, if you want the per-stream
102+
active setting
103+
:param timeout: The timeout to use for this request
104+
:return: True if the capsule is active
105+
"""
106+
if stream_id is None:
107+
req = f"/api/plugins/{capsule_name}/active"
108+
else:
109+
req = f"/api/streams/{stream_id}/plugins/{capsule_name}/active"
110+
capsules_active, _ = self._get_json(req, timeout)
111+
return capsules_active
112+
113+
def set_capsule_active(self, *, capsule_name, stream_id=None,
114+
active: Optional[bool],
115+
timeout=DEFAULT_TIMEOUT):
116+
"""Sets whether or not the capsule is active. If a capsule is active, it
117+
will be run on frames.
118+
119+
:param capsule_name: The name of the capsule to set activity for
120+
:param stream_id: The ID of the stream, if you want to set the
121+
per-stream active setting
122+
:param active: True if the capsule should be set to active
123+
:param timeout: The timeout to use for this request
124+
"""
125+
if stream_id is None:
126+
req = f"/api/plugins/{capsule_name}/active"
127+
else:
128+
req = f"/api/streams/{stream_id}/plugins/{capsule_name}/active"
129+
130+
active_json = json.dumps(active)
131+
132+
self._put_json(req, timeout, active_json)

0 commit comments

Comments
 (0)