hyperstudy 0.4.2__py3-none-any.whl → 0.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hyperstudy/__init__.py +11 -1
- hyperstudy/experiments.py +5 -0
- hyperstudy/models.py +129 -4
- {hyperstudy-0.4.2.dist-info → hyperstudy-0.4.3.dist-info}/METADATA +33 -1
- {hyperstudy-0.4.2.dist-info → hyperstudy-0.4.3.dist-info}/RECORD +7 -7
- {hyperstudy-0.4.2.dist-info → hyperstudy-0.4.3.dist-info}/WHEEL +0 -0
- {hyperstudy-0.4.2.dist-info → hyperstudy-0.4.3.dist-info}/licenses/LICENSE +0 -0
hyperstudy/__init__.py
CHANGED
|
@@ -31,13 +31,17 @@ from .exceptions import (
|
|
|
31
31
|
)
|
|
32
32
|
from .models import (
|
|
33
33
|
AgentConfig,
|
|
34
|
+
Cluster,
|
|
35
|
+
ClusterRule,
|
|
34
36
|
ComponentType,
|
|
35
37
|
DisconnectTimeout,
|
|
38
|
+
Distribution,
|
|
36
39
|
EngineTurnDetection,
|
|
37
40
|
Experiment,
|
|
38
41
|
ExperimenterMessageStyle,
|
|
39
42
|
FocusComponent,
|
|
40
43
|
GlobalComponentType,
|
|
44
|
+
Group,
|
|
41
45
|
Guardrails,
|
|
42
46
|
InstructionsPage,
|
|
43
47
|
Persona,
|
|
@@ -49,6 +53,7 @@ from .models import (
|
|
|
49
53
|
Role,
|
|
50
54
|
State,
|
|
51
55
|
TransitionRules,
|
|
56
|
+
VariableDefinition,
|
|
52
57
|
VoiceTranscription,
|
|
53
58
|
VoiceTurnTaking,
|
|
54
59
|
WaitingRoomConfig,
|
|
@@ -63,7 +68,7 @@ from .models import (
|
|
|
63
68
|
waiting,
|
|
64
69
|
)
|
|
65
70
|
|
|
66
|
-
__version__ = "0.4.
|
|
71
|
+
__version__ = "0.4.3"
|
|
67
72
|
|
|
68
73
|
__all__ = [
|
|
69
74
|
"HyperStudy",
|
|
@@ -98,6 +103,11 @@ __all__ = [
|
|
|
98
103
|
"VoiceTranscription",
|
|
99
104
|
"ExperimenterMessageStyle",
|
|
100
105
|
"TransitionRules",
|
|
106
|
+
"Group",
|
|
107
|
+
"Cluster",
|
|
108
|
+
"ClusterRule",
|
|
109
|
+
"VariableDefinition",
|
|
110
|
+
"Distribution",
|
|
101
111
|
"WaitingRoomConfig",
|
|
102
112
|
"DisconnectTimeout",
|
|
103
113
|
"InstructionsPage",
|
hyperstudy/experiments.py
CHANGED
|
@@ -211,6 +211,11 @@ class ExperimentMixin:
|
|
|
211
211
|
``{"valid": True}`` on success, or ``{"valid": False, "errors": [...]}``
|
|
212
212
|
with a list of issues.
|
|
213
213
|
|
|
214
|
+
Set ``runtime`` explicitly when the definition has
|
|
215
|
+
``variable_definitions``: servers older than v0.7.32 do not default
|
|
216
|
+
it to ``"v2"`` here the way :meth:`create_experiment` does, and
|
|
217
|
+
report variable definitions on any other runtime as an error.
|
|
218
|
+
|
|
214
219
|
Args:
|
|
215
220
|
experiment: An :class:`Experiment` or a raw config dict.
|
|
216
221
|
"""
|
hyperstudy/models.py
CHANGED
|
@@ -37,10 +37,13 @@ _FREEFORM_MAP_FIELDS = frozenset({
|
|
|
37
37
|
# (engineTurnDetection), and names the researcher chose (cognition contexts,
|
|
38
38
|
# stimulus mappings, free-form metadata). Matching on position, not the bare
|
|
39
39
|
# key, keeps a variable or role that happens to be named "metadata" a variable.
|
|
40
|
+
# A variable definition's constant ``value`` and a list distribution's
|
|
41
|
+
# ``values`` are researcher data, so their keys are kept too.
|
|
40
42
|
_VERBATIM_FIELDS = frozenset({
|
|
41
43
|
(None, "extraParams"), (None, "cognition"), (None, "stimulusMappings"),
|
|
42
44
|
(None, "metadata"), (None, "prolific_config"),
|
|
43
45
|
("voiceTurnTaking", "engineTurnDetection"),
|
|
46
|
+
("variableDefinitions", "value"), ("distribution", "values"),
|
|
44
47
|
})
|
|
45
48
|
|
|
46
49
|
# Experiment fields the backend stores under snake_case names.
|
|
@@ -151,14 +154,23 @@ class FocusComponent(_Model):
|
|
|
151
154
|
|
|
152
155
|
|
|
153
156
|
class TransitionRules(_Model):
|
|
154
|
-
"""Rules governing how the experiment transitions from a state.
|
|
157
|
+
"""Rules governing how the experiment transitions from a state.
|
|
158
|
+
|
|
159
|
+
On the V2 runner a ``"TIMED"`` state can draw its duration from a random
|
|
160
|
+
variable instead of a fixed value: set ``variable_id`` to the id of a
|
|
161
|
+
:class:`VariableDefinition` with ``kind="random"``.
|
|
162
|
+
"""
|
|
155
163
|
|
|
156
164
|
type: Optional[str] = None
|
|
157
165
|
duration_ms: Optional[int] = Field(default=None, ge=0)
|
|
166
|
+
variable_id: Optional[str] = None
|
|
158
167
|
|
|
159
168
|
|
|
160
169
|
class State(_Model):
|
|
161
|
-
"""An experiment state — a single screen/phase.
|
|
170
|
+
"""An experiment state — a single screen/phase.
|
|
171
|
+
|
|
172
|
+
``cluster_id`` (V2 runner) makes the state a member of a :class:`Cluster`.
|
|
173
|
+
"""
|
|
162
174
|
|
|
163
175
|
id: str = Field(min_length=1)
|
|
164
176
|
name: Optional[str] = None
|
|
@@ -166,6 +178,108 @@ class State(_Model):
|
|
|
166
178
|
focus_component: Optional[FocusComponent] = None
|
|
167
179
|
transition_rules: Optional[TransitionRules] = None
|
|
168
180
|
global_components_visibility: Optional[dict[str, bool]] = None
|
|
181
|
+
cluster_id: Optional[str] = None
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class Group(_Model):
|
|
185
|
+
"""A group of states that run together.
|
|
186
|
+
|
|
187
|
+
``children`` are state ids, in run order. ``order`` places the group
|
|
188
|
+
among the top-level states (lone states and groups share one sequence).
|
|
189
|
+
``cluster_id`` (V2 runner) makes the whole group a member of a
|
|
190
|
+
:class:`Cluster`, moving as one unit; its states can carry their own
|
|
191
|
+
``cluster_id`` to be randomized within the group.
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
id: str = Field(min_length=1)
|
|
195
|
+
name: Optional[str] = None
|
|
196
|
+
order: Optional[int] = Field(default=None, ge=0)
|
|
197
|
+
children: Optional[list[str]] = None
|
|
198
|
+
cluster_id: Optional[str] = None
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class ClusterRule(_Model):
|
|
202
|
+
"""How a cluster orders its members.
|
|
203
|
+
|
|
204
|
+
``type``: ``"shuffle"`` (a uniformly random order) or ``"keep"`` (the
|
|
205
|
+
authored order). ``across_groups``, for a cluster used inside groups:
|
|
206
|
+
``"independent"`` (default; each group draws its own order) or
|
|
207
|
+
``"same"`` (one order applied to every group using the cluster, which
|
|
208
|
+
must then all have the same number of members).
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
type: str # "shuffle" | "keep"
|
|
212
|
+
across_groups: Optional[str] = None # "independent" (default) | "same"
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class Cluster(_Model):
|
|
216
|
+
"""A randomization cluster (V2 runner only; ignored on the legacy runner).
|
|
217
|
+
|
|
218
|
+
Used only while the experiment's ``randomize_states`` is True; with it
|
|
219
|
+
False the clusters are kept but rooms run the listed order.
|
|
220
|
+
|
|
221
|
+
States and groups join a cluster by setting ``cluster_id`` to its ``id``.
|
|
222
|
+
A cluster applies among siblings: the top-level items (lone states and
|
|
223
|
+
whole groups), or the states inside one group. Members trade places
|
|
224
|
+
among the positions they occupy; everything else stays where it is. Each
|
|
225
|
+
room draws its order once, so everyone in the room runs the same order.
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
id: str = Field(default_factory=_new_id, min_length=1)
|
|
229
|
+
name: Optional[str] = None
|
|
230
|
+
color: Optional[str] = None
|
|
231
|
+
rule: ClusterRule
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class Distribution(_Model):
|
|
235
|
+
"""The distribution a random variable draws from.
|
|
236
|
+
|
|
237
|
+
- ``type="uniform"``: ``min``, ``max``
|
|
238
|
+
- ``type="normal"``: ``mean``, ``sd``; optional ``min`` / ``max`` truncate it
|
|
239
|
+
- ``type="exponential"``: ``mean``; ``min`` (default 0) plus an exponential
|
|
240
|
+
with this mean, optionally cut at ``max``
|
|
241
|
+
- ``type="list"``: ``values`` and ``sampling`` (``"with_replacement"``,
|
|
242
|
+
``"without_replacement"`` — a deck reshuffled when exhausted — or
|
|
243
|
+
``"sequential"``, in order, wrapping)
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
type: str # "uniform" | "normal" | "exponential" | "list"
|
|
247
|
+
min: Optional[float] = None
|
|
248
|
+
max: Optional[float] = None
|
|
249
|
+
mean: Optional[float] = None
|
|
250
|
+
sd: Optional[float] = Field(default=None, gt=0)
|
|
251
|
+
values: Optional[list[Any]] = Field(default=None, min_length=1, max_length=1000)
|
|
252
|
+
sampling: Optional[str] = None # list: with_replacement | without_replacement | sequential
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class VariableDefinition(_Model):
|
|
256
|
+
"""A variable the experiment defines (V2 runner only).
|
|
257
|
+
|
|
258
|
+
``kind`` decides which fields apply:
|
|
259
|
+
|
|
260
|
+
- ``"constant"``: ``value`` (text, a number, true/false, a list or a dict)
|
|
261
|
+
- ``"random"``: ``distribution``, ``draw`` (``"per_use"``, the default: a
|
|
262
|
+
fresh value for each state that takes its duration from it;
|
|
263
|
+
``"per_room"``: one value for the room) and ``round`` (decimals kept,
|
|
264
|
+
default 0). Values are drawn when the room is planned, so everyone in
|
|
265
|
+
the room gets the same ones.
|
|
266
|
+
- ``"computed"``: ``expr``, an expression over other variables
|
|
267
|
+
|
|
268
|
+
``name`` is what component text (``{name}``) and expressions read; ``id``
|
|
269
|
+
is what a TIMED state's ``TransitionRules.variable_id`` references, and is
|
|
270
|
+
generated when omitted. The server refuses non-empty definitions unless
|
|
271
|
+
the experiment's ``runtime`` is ``"v2"``, and refuses a save that makes
|
|
272
|
+
them invalid (``ValidationError``, messages in ``details["errors"]``).
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
id: str = Field(default_factory=_new_id, min_length=1)
|
|
276
|
+
name: str = Field(pattern=r"^[A-Za-z_][A-Za-z0-9_]{0,63}$")
|
|
277
|
+
kind: str # "constant" | "random" | "computed"
|
|
278
|
+
value: Optional[Any] = None
|
|
279
|
+
distribution: Optional[Distribution] = None
|
|
280
|
+
draw: Optional[str] = None # random: "per_use" (default) | "per_room"
|
|
281
|
+
round: Optional[int] = Field(default=None, ge=0, le=6)
|
|
282
|
+
expr: Optional[str] = Field(default=None, min_length=1, max_length=2000)
|
|
169
283
|
|
|
170
284
|
|
|
171
285
|
class Role(_Model):
|
|
@@ -371,10 +485,15 @@ class Experiment(_Model):
|
|
|
371
485
|
name: str = Field(min_length=1)
|
|
372
486
|
description: Optional[str] = None
|
|
373
487
|
required_participants: Optional[int] = Field(default=None, ge=1)
|
|
374
|
-
|
|
488
|
+
# "v2" (the server's default for new experiments) or "v1" (legacy).
|
|
489
|
+
# Agents, clusters and variable_definitions need "v2".
|
|
490
|
+
runtime: Optional[str] = None
|
|
375
491
|
agent_config: Optional[AgentConfig] = None
|
|
376
|
-
randomize_states: Optional[bool] = None
|
|
492
|
+
randomize_states: Optional[bool] = None # legacy: shuffle per participant; v2: use clusters
|
|
377
493
|
states: Optional[list[State]] = None
|
|
494
|
+
groups: Optional[list[Group]] = None
|
|
495
|
+
clusters: Optional[list[Cluster]] = Field(default=None, max_length=100)
|
|
496
|
+
variable_definitions: Optional[list[VariableDefinition]] = Field(default=None, max_length=500)
|
|
378
497
|
roles: Optional[dict[str, Role]] = None
|
|
379
498
|
global_components: Optional[dict[GlobalComponentType, dict[str, Any]]] = None
|
|
380
499
|
variables: Optional[dict[str, Any]] = None
|
|
@@ -561,12 +680,18 @@ __all__ = [
|
|
|
561
680
|
"State",
|
|
562
681
|
"FocusComponent",
|
|
563
682
|
"TransitionRules",
|
|
683
|
+
"Group",
|
|
564
684
|
"Role",
|
|
565
685
|
"WaitingRoomConfig",
|
|
566
686
|
"DisconnectTimeout",
|
|
567
687
|
"InstructionsPage",
|
|
568
688
|
"PostExperimentQuestionnaire",
|
|
569
689
|
"ExperimenterMessageStyle",
|
|
690
|
+
# Randomization and variables (V2 runner)
|
|
691
|
+
"Cluster",
|
|
692
|
+
"ClusterRule",
|
|
693
|
+
"VariableDefinition",
|
|
694
|
+
"Distribution",
|
|
570
695
|
# Agent models
|
|
571
696
|
"AgentConfig",
|
|
572
697
|
"PromptLayer",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hyperstudy
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Python SDK for the HyperStudy experiment platform API
|
|
5
5
|
Project-URL: Homepage, https://hyperstudy.io
|
|
6
6
|
Project-URL: Documentation, https://docs.hyperstudy.io/developers/python-sdk
|
|
@@ -179,6 +179,38 @@ info = hs.create_experiment(experiment=exp)
|
|
|
179
179
|
|
|
180
180
|
Component factories cover `show_text`, `show_image`, `show_video`, `vas_rating`, `text_input`, `multiple_choice`, `waiting`, `likert_scale`, `ranking`. For other component types, construct directly: `FocusComponent(type=ComponentType.X, config={...})`. See the [Experiment Authoring guide](https://docs.hyperstudy.io/experimenters/api-access/experiment-authoring) for the full reference.
|
|
181
181
|
|
|
182
|
+
### Randomization and variables (V2 runner)
|
|
183
|
+
|
|
184
|
+
Clusters randomize the order of states and groups once per room while `randomize_states=True`; with it `False` the clusters are kept but rooms run the listed order. Variable definitions hold constants, random draws and computed values. Both need `runtime="v2"` (the server's default for new experiments). On the legacy runner, `randomize_states=True` shuffles each participant's order instead.
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from hyperstudy import Cluster, ClusterRule, Distribution, TransitionRules, VariableDefinition
|
|
188
|
+
|
|
189
|
+
iti = VariableDefinition(
|
|
190
|
+
name="iti_ms", kind="random",
|
|
191
|
+
distribution=Distribution(type="uniform", min=500, max=1500),
|
|
192
|
+
)
|
|
193
|
+
exp = Experiment(
|
|
194
|
+
name="Randomized study",
|
|
195
|
+
runtime="v2",
|
|
196
|
+
randomize_states=True,
|
|
197
|
+
clusters=[Cluster(id="block", rule=ClusterRule(type="shuffle"))],
|
|
198
|
+
variable_definitions=[
|
|
199
|
+
VariableDefinition(name="endowment", kind="constant", value=10),
|
|
200
|
+
VariableDefinition(name="doubled", kind="computed", expr="endowment * 2"),
|
|
201
|
+
iti,
|
|
202
|
+
],
|
|
203
|
+
states=[
|
|
204
|
+
State(id="a", cluster_id="block", focus_component=show_text("You have {endowment}")),
|
|
205
|
+
State(id="b", cluster_id="block", focus_component=show_text("Doubled: {doubled}")),
|
|
206
|
+
State(id="pause", focus_component=show_text("+"),
|
|
207
|
+
transition_rules=TransitionRules(type="TIMED", variable_id=iti.id)),
|
|
208
|
+
],
|
|
209
|
+
)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The server refuses a create or update that would make clusters or variables invalid, raising `ValidationError` with the reasons in `err.details["errors"]`.
|
|
213
|
+
|
|
182
214
|
## Deployments
|
|
183
215
|
|
|
184
216
|
```python
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
hyperstudy/__init__.py,sha256=
|
|
1
|
+
hyperstudy/__init__.py,sha256=RVX7QgHV4AXn0V40p-i2zsXv1bT5kYA7AgVnlRuTgDs,2545
|
|
2
2
|
hyperstudy/_dataframe.py,sha256=8pjuMG8phMv8vwdY7sgZ-aF_6_o0UMgP2XXNp5muZ0s,3620
|
|
3
3
|
hyperstudy/_display.py,sha256=5svr4NFOUJkVif57-xJzrXNOSdA5O9tKesu8UhE_jYo,1896
|
|
4
4
|
hyperstudy/_downloads.py,sha256=8s-Ml0oK_3f5CNn9hSp0z5d1oyDBR7ldPYVPbDo0zss,2616
|
|
@@ -7,10 +7,10 @@ hyperstudy/_pagination.py,sha256=2NbvNGW_jFQkYquSTi3SNkAmGgsbKop7J9LkGaZWwWA,181
|
|
|
7
7
|
hyperstudy/_types.py,sha256=nREuLxEe4ylnyxRPyR1kgBh0V4fDKf5OmfiLEmTkg-o,734
|
|
8
8
|
hyperstudy/client.py,sha256=DRKDmLND65bxXAIBO9EDK2IikX6RJ_6O0GgmyI6ISTI,40319
|
|
9
9
|
hyperstudy/exceptions.py,sha256=z_1Ngiq-RU-1yyDI_JqvQ5CvYm2jQ_lyJ9TUbqUKKv8,1529
|
|
10
|
-
hyperstudy/experiments.py,sha256=
|
|
11
|
-
hyperstudy/models.py,sha256=
|
|
10
|
+
hyperstudy/experiments.py,sha256=TkWHncrQmUlEKAmVHHCeXwekSFDqQ6lxu81gW6J-cOE,8973
|
|
11
|
+
hyperstudy/models.py,sha256=X3y5kpBH1YZLp9VYoZ8ChobIYC_oIKH5PoP73GyBrCk,25691
|
|
12
12
|
hyperstudy/personas.py,sha256=T4cbI0wWfokAthxKzgM73NA_we3mBtR-j_lcn3iYl4Q,5328
|
|
13
|
-
hyperstudy-0.4.
|
|
14
|
-
hyperstudy-0.4.
|
|
15
|
-
hyperstudy-0.4.
|
|
16
|
-
hyperstudy-0.4.
|
|
13
|
+
hyperstudy-0.4.3.dist-info/METADATA,sha256=JCtqw_t8ZDw13s_HEIDvpuKyjH2lpblfS2iqcQnFGjs,12049
|
|
14
|
+
hyperstudy-0.4.3.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
15
|
+
hyperstudy-0.4.3.dist-info/licenses/LICENSE,sha256=WJdwRhBIOiiQ6lyK4l95u5IJYuuT-XxzwYRraS31NME,1067
|
|
16
|
+
hyperstudy-0.4.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|